Go--发起HTTP请求

发布时间 2023-06-26 17:48:27作者: 心恩惠动

一、HTTP请求

根据 HTTP 标准,HTTP 请求可以使用多种请求方法。在日常开发中大多数会用到 5 种请求方法: GET、POST、PUT、PATCH 和 DELETE

方法 描述
GET 请求指定的页面信息,并返回实体主体
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改
PUT 从客户端向服务器传送的数据取代指定的文档的内容
DELETE 请求服务器删除指定的页面
PATCH 是对 PUT 方法的补充,用来对已知资源进行局部更新

 

在一次http请求(request)中可携带参数的地方:

部分 用途
URL部分 即以?和&分割的url参数
header部分 在http头中的字段,比如常用的cookie
content-body部分 请求正文,如果是get请求则为空;如果是post请求,则请求头中的Content-Type字段规定了content-body部分应该怎么被解析

 

二、GET请求

2.1 不带参数的GET请求

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func HttpGet(url string) []byte {
    //发起请求
    res, err := http.Get(url)
    if err != nil {
        fmt.Println("get请求失败:", err)
    }
    //延迟关闭(返回response的body尽量关闭,避免内存泄露)
    defer res.Body.Close()
    // 请求头
    fmt.Println(res.Header)
    // 请求相应码
    fmt.Println(res.Status)

    //读取body数据
    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Println("读取body失败:", err)
        return nil
    }

    return body
}

func main() {
    UrlPath := "https://xxx/instance"
    body := HttpGet(UrlPath)
    //打印body,以字符串形式
    fmt.Printf(string(body))
    
}

 

2.2 带参数的GET请求

2.2.1 静态参数

若参数是固定的,则将1.1中的UrlPath设置为完整的请求即可,例: UrlPath := "https://xxx/instance?name=xxx&age=18" 

 

2.2.2 动态参数
package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func HttpGetUrl(url string) []byte {
    //正常来说,GET请求所有的参数都应该是放在url上,body请求体中是没有数据的
    //请求头可能会携带token之类的参数

    //新建一个GET请求
    request, err := http.NewRequest("GET", url, nil)
    if err != nil {
        panic(err)
    }

    //请求头部信息
    //Set时候,如果原来这一项已存在,后面的就修改已有的
    //Add时候,如果原本不存在,则添加,如果已存在,就不做任何修改
    //最终服务端获取的应该是token2
    request.Header.Set("User-Agent", "自定义浏览器1...")
    request.Header.Set("User-Agent", "自定义浏览器2...")
    request.Header.Add("Host", "www.xxx.com")

    //header:  map[User-Agent:[自定义浏览器2...]]
    request.Header.Add("name", "alnk")
    request.Header.Add("name", "alnk2")

    //header:  map[Name:[alnk alnk2] User-Agent:[自定义浏览器2...]]
    request.Header.Add("Authorization", "token1...") //token

    fmt.Println("header: ", request.Header)

    //url参数
    query := request.URL.Query()
    query.Add("id", "1")
    query.Add("id", "2")
    query.Add("name", "wan")
    request.URL.RawQuery = query.Encode()
    fmt.Println("request.URL: ", request.URL) //request.URL:  https://xxx/instance?id=1&id=2&name=wan

    //发送请求给服务端,实例化一个客户端
    client := &http.Client{}
    res, err := client.Do(request)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()

    //服务端返回数据
    b, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    return b
}

func main() {
    UrlPath := "https://xxx/instance"
    body := HttpGetUrl(UrlPath)
    //打印body,以字符串形式
    fmt.Printf(string(body))

}

 

2.3 解析json类型的返回结果

有些请求返回的数据是json格式,无法直接使用,需要进行反序列化

type result struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    UrlPath := "https://xxx/instance"
    body := HttpGetUrl(UrlPath)
    //打印body,以字符串形式
    fmt.Printf(string(body))

    var res result
    err := json.Unmarshal(body, &res)
    if err != nil {
        fmt.Println(err)
        return
    }
    // 拿到数据以后,就可以自行处理数据了,比如存到数据库里
    fmt.Printf("%#v", res)
}

 

三、POST请求

3.1 Content-Type类型

Content-Type 用途
application/x-www-form-urlencoded 默认的方式, 比如 title=test&id=1010
multipart/form-data 如果你的请求里包含多个文件等二进制信息,则form 的 enctyped 需要等于这个值,浏览器生成一个 boundary 用于分割不同的字段
application/json 以json格式传送
raw 纯二进制格式,这需要服务器拿到消息后自己定义解析方式,比如protobuf

 

 

3.2 使用 http.Post() + application/x-www-form-urlencoded

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "strings"
)

func HttpPost(urlP string) []byte {
    //url.Values用来存放body参数,无参数不加
    urlValues := url.Values{} //urlValues ---> map[string][]string
    urlValues.Add("user", "test")
    urlValues.Add("password", "test123")
    //编码
    reqBody := urlValues.Encode()

    //最终http报文里面的body是 user=test&password=test123
    resp, err := http.Post(urlP, "application/x-www-form-urlencoded", strings.NewReader(reqBody))
    if err != nil {
        fmt.Println(err)
        return nil
    }

    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)

    return body
}

func main() {
    var urlP = "https://www.xxx.com/json"
    body := HttpPost(urlP)
    fmt.Println(string(body))
}

 

3.3 使用 http.Post() + application/json

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

func HttpPost(urlP string) []byte {
    // 参数
    data := make(map[string]interface{})
    data["user"] = "test"
    data["password"] = "test123"

    // 序列化
    bytesData, _ := json.Marshal(data)
    
    resp, err := http.Post(urlP, "application/json", bytes.NewReader(bytesData))
    if err != nil {
        fmt.Println(err)
        return nil
    }

    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)

    return body
}

func main() {
    var urlP = "https://www.xxx.com/json"
    body := HttpPost(urlP)
    fmt.Println(string(body))
}

 

3.4 http.PostForm()

提交post表单

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
)

func HttpPost(urlP string) []byte {
    urlValues := url.Values{}
    urlValues.Add("user", "test")
    urlValues.Add("password", "test123")

    resp, err := http.PostForm(urlP, urlValues)
    //resp, err := http.PostForm(urlP, url.Values{
    //    "user": {"test"},
    //    "password": {"test123"},
    //})
    if err != nil {
        fmt.Println(err)
        return nil
    }

    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)

    return body
}

func main() {
    var urlP = "https://www.xxx.com/json"
    body := HttpPost(urlP)
    fmt.Println(string(body))
}

 

四、http.NewRequest()

如2.2.2,复杂的http请求,可以通过http.NewRequest 来创建请求,再用client.Do发送,http.NewRequest支持各种请求方法

get请求如2.2.2

 

4.1 POST

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
    "strings"
)

func HttpPost(urlP string) []byte {
    //请求body
    urlMap := url.Values{}
    urlMap.Add("user", "test")
    urlMap.Add("password", "test123")

    //新建请求
    request, err := http.NewRequest("POST", urlP, strings.NewReader(urlMap.Encode()))
    if err != nil {
        fmt.Println(err)
        return nil
    }
    fmt.Println("request.url: ", request.URL)
    fmt.Println("request.method: ", request.Method)

    //请求头部信息
    request.Header.Add("Authorization", "token1...")
    //post formdata表单请求
    request.Header.Add("Content-Type", "application/x-www-form-urlencoded")

    ////发送json格式的参数
    //data := map[string]interface{}{
    //    "user":     "test",
    //    "password": 123,
    //}
    //// 序列化
    //bytesData, _ := json.Marshal(data)
    //request, _ := http.NewRequest("POST", urlP, strings.NewReader(string(bytesData)))
    //请求头设置
    //request.Header.Add("Authorization", "token1...")       //token
    //request.Header.Add("Content-Type", "application/json") //json请求

    //实例化一个客户端
    client := &http.Client{}
    //发送请求到服务端
    resp, err := client.Do(request)
    if err != nil {
        fmt.Println(err)
        return nil
    }

    defer resp.Body.Close()
    body, _ := ioutil.ReadAll(resp.Body)

    return body
}

func main() {
    var urlP = "https://www.xxx.com/json"
    body := HttpPost(urlP)
    fmt.Println(string(body))
}

 

4.2 DELETE

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

func HttpDelete(urlD string) []byte {
    //携带tonken
    //通过ID删除
    request, err := http.NewRequest("DELETE", urlD, nil)
    if err != nil {
        panic(err)
    }

    //请求头部信息
    request.Header.Add("Authorization", "token1...") //token

    //url参数
    query := request.URL.Query()
    query.Add("id", "1")
    query.Add("id", "2")
    query.Add("id", "3")
    request.URL.RawQuery = query.Encode()

    //发送请求给服务端
    client := &http.Client{}
    res, err := client.Do(request)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()

    //服务端返回数据
    b, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }

    return b
}

func main() {
    var urlD = "https://www.xxx.com/json"
    body := HttpDelete(urlD)
    fmt.Println(string(body))
}

 

4.3 PUT

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "strings"
)

func HttpPut(urlP string) []byte {
    //通过ID修改用户数据
    //数据格式化
    data := map[string]interface{}{
        "name": "wang",
        "age":  18,
    }
    dataStr, err := json.Marshal(data)
    if err != nil {
        panic(err)
    }

    //创建一个新的请求
    request, err := http.NewRequest("PUT", urlP, strings.NewReader(string(dataStr)))
    if err != nil {
        panic(err)
    }

    //请求头设置
    request.Header.Add("Authorization", "token1...")       //token
    request.Header.Add("Content-Type", "application/json") //json请求

    //url参数
    query := request.URL.Query()
    query.Add("id", "1")
    request.URL.RawQuery = query.Encode()

    //发送请求给服务端
    client := &http.Client{}
    res, err := client.Do(request)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()

    //服务端返回数据
    b, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    return b
}

func main() {
    var urlP = "https://www.xxx.com/json"
    body := HttpPut(urlP)
    fmt.Println(string(body))
}

 

4.4 PATCH

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "strings"
)

func HttpPatch(urlP string) []byte {

    data := map[string]interface{}{
        "user":     "test",
        "password": 123,
    }
    dataStr, err := json.Marshal(data)
    if err != nil {
        panic(err)
    }

    //创建一个新的请求
    request, err := http.NewRequest("PATCH", urlP, strings.NewReader(string(dataStr)))
    if err != nil {
        panic(err)
    }

    //请求头设置
    request.Header.Add("Authorization", "token1...")       //token
    request.Header.Add("Content-Type", "application/json") //json请求
    

    //发送请求给服务端
    client := &http.Client{}
    res, err := client.Do(request)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()

    //服务端返回数据
    b, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    return b
}

func main() {
    var urlP = "https://www.xxx.com/json"
    body := HttpPatch(urlP)
    fmt.Println(string(body))
}