golang 使用net/http的client请求数据
目录
通常我们直接通过 client 向 http server 发送请求时,需要注意几点:
- 1.请求方法,GET 还是 POST 还是有不同的,POST 需要携带 请求体数据,另外两者共性的是,在请求首部处需要指定对应字段
- 2.如果是复杂点的请求,建议还是通过 http.Client 执行,而不通过 http.Get()/http.Post() 发送请求
- 3.请求的 server 需要注意是否是 明文、加密 的
1.简单请求
1.1 Get请求
对于这种简单请求,通常我们不用关心 content-type 传输格式是明文还是加密,直接通过 http.Get() 发送请求就可以了,下面是代码示例。
func TestSimpleGetClient(t *testing.T) { resp, _ := http.Get("http://172.22.22.22:8000/api/v1/task/info") body := resp.Body bodyBytes, _ := io.ReadAll(body) // print resp body fmt.Printf("%s", bodyBytes) // unmarshal to app var m map[string]interface{} _ = json.Unmarshal(bodyBytes, &m) fmt.Printf("m: %v", m) }
http.Get()
func Get(url string) (resp *Response, err error) { return DefaultClient.Get(url) } var DefaultClient = &Client{}
可以看出,该方法实际也是基于一个预先设定的默认 client 发送 Get 请求, 传入一个 url 就可以了。
1.2 POST请求
参照 Get 简单请求,此处主要需注意按照传入参数要求给定,下面是示例。
func TestSimplePostClient(t *testing.T) { body := map[string]string{ "key": "value", } bodyBytes, _ := json.Marshal(body) reqBody := bytes.NewReader(bodyBytes) resp, _ := http.Post("http://172.22.22.22:8000/api/v1/task/info", "application/json", reqBody) // read resp body respBody, _ := io.ReadAll(resp.Body) // 通常响应都是json格式,所以需要转回结构体或map var m map[string]interface{} _ = json.Unmarshal(respBody, &m) // 使用map fmt.Printf("m: %v", m) }
http.Post()
func Post(url, contentType string, body io.Reader) (resp *Response, err error) { return DefaultClient.Post(url, contentType, body) } // DefaultClient is the default Client and is used by Get, Head, and Post. var DefaultClient = &Client{}
request body 的转换
只要实现了 io.Reader 接口 的都可以
// io包 // Implementations must not retain p. type Reader interface { Read(p []byte) (n int, err error) }
所以我们的 request body 应该通过实现了 Reader 接口的传入,我们常用的有以下:
- bytes
- buffers
- strings
- jsonReader
比如我们有这样一个构建的 map 结构的请求体:
body := map[string]string{ "key": "value", }
上述的这些实现 Reader 接口的有如下方法:
jsonBody, _ := json.Marshal(body) // 1.bytes bytesReader := bytes.NewReader(jsonBody) // 2.strings stringsReader := strings.NewReader(string(jsonBody)) // 3.buffers bufferIns := bytes.NewBuffer(make([]byte, 1024)) bufferIns.Read(jsonBody)
2.复杂请求-用 http.Client
上面的主要针对一些简单的 http 请求,如果是更复杂的请求,如我们需要指定更多的请求首部等信息,这里就需要用到自己创建的 Client 实例,下面看看示例。
2.1 Get请求
func TestGetClient(t *testing.T) { // 1.create client instance myClient := http.Client{} // 2.build request // 2.1 Get req getReq, _ := http.NewRequest(http.MethodGet, "http://172.22.22.22:8000/api/v1/task/info", nil) // build headers headers := map[string]string{ "Authorization": fmt.Sprintf("Bearer %s", "12345678"), "Content-Type": "application/json", } // add to req for k, v := range headers { getReq.Header.Set(k, v) } // 3.client exec req resp, _ := myClient.Do(getReq) // read resp body respBody, _ := io.ReadAll(resp.Body) // 通常响应都是json格式,所以需要转回结构体或map var m map[string]interface{} _ = json.Unmarshal(respBody, &m) // 使用map fmt.Printf("m: %v", m) }
2.2 Post请求
func TestPostClient(t *testing.T) { // 1.create client instance myClient := http.Client{} // 2.build request // 2.2 Post req // build body body := map[string]string{ "key": "value", } bodyBytes, _ := json.Marshal(body) reqBody := bytes.NewReader(bodyBytes) postReq, _ := http.NewRequest(http.MethodPost, "http://172.22.22.22:8000/api/v1/task/info", reqBody) // build headers headers := map[string]string{ "Authorization": fmt.Sprintf("Bearer %s", "12345678"), "Content-Type": "application/json", } // add to req for k, v := range headers { postReq.Header.Set(k, v) } // 3.client exec req resp, _ := myClient.Do(postReq) // read resp body respBody, _ := io.ReadAll(resp.Body) // 通常响应都是json格式,所以需要转回结构体或map var m map[string]interface{} _ = json.Unmarshal(respBody, &m) // 使用map fmt.Printf("m: %v", m) }
3.加密请求
如果发送 https,显然上面已经不满足需求了,这时需要注意在 client 实例中指定 transport。
func TestHttpsClient(t *testing.T) { // 1.create client myCLient := http.Client{ Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}, CheckRedirect: nil, Jar: nil, Timeout: time.Second * 10, } // 2.这里仅发送简单请求, 如复杂请求请先构建 request resp, _ := myCLient.Get("http://172.22.22.22:8000/api/v1/task/info") body := resp.Body bodyBytes, _ := io.ReadAll(body) // print resp body fmt.Printf("%s", bodyBytes) // unmarshal to app var m map[string]interface{} _ = json.Unmarshal(bodyBytes, &m) fmt.Printf("m: %v", m) }
4.multiPart示例 & postForm示例
参考:
multiPart
func newfileUploadRequest(uri string, params map[string]string, paramName, path string) (*http.Request, error) { file, err := os.Open(path) if err != nil { return nil, err } defer file.Close() body := &bytes.Buffer{} writer := multipart.NewWriter(body) part, err := writer.CreateFormFile(paramName, path) if err != nil { return nil, err } _, err = io.Copy(part, file) for key, val := range params { _ = writer.WriteField(key, val) } err = writer.Close() if err != nil { return nil, err } request, err := http.NewRequest("POST", uri, body) request.Header.Set("Content-Type", writer.FormDataContentType()) return request, err }
http.PostForm
func httpPostForm() { resp, err := http.PostForm("http://www.01happy.com/demo/accept.php", url.Values{"key": {"Value"}, "id": {"123"}}) if err != nil { // handle error } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { // handle error } fmt.Println(string(body)) }
更多示例:
client 简单 POST 请求
func main() { reqBody, _ := json.Marshal(map[string]string{"key1": "val1", "key2": "val2"}) resp, _ := http.Post(":8091", "application/json", bytes.NewReader(reqBody)) defer resp.Body.Close() respBody, _ := io.ReadAll(resp.Body) fmt.Printf("resp: %s", respBody) }
代码:
package main import ( "bytes" "crypto/sha256" "crypto/tls" "encoding/base64" "encoding/json" "fmt" "io" "io/ioutil" "net/http" "sync" "time" ) func main() { sessionID, _ := checkIn() fmt.Println("sessionID:", sessionID) if sessionID != "" { getArsModels(sessionID) } } var ( username = "admin" deviceID = "22241dc1-a7fc-d69e-5467-xxxxxxxxxxxx" baseURL = "https://xxx:xxx" v1URL = "/xxx/v1/" sessionURL = baseURL + v1URL + "sessions" arsModelsURL = baseURL + v1URL + fmt.Sprintf("devices/%s/xxx/xrs", deviceID) ) var ( once sync.Once client *http.Client ) func init() { getHttpClient() } func getHttpClient() *http.Client { once.Do(func() { client = &http.Client{ // 跳过证书验证 Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, } }) return client } // Get func getArsModels(sessionID string) { headers := map[string]string{ "Content-Type": "application/json", "Accept-Type": "application/json", "User-Agent": "QKAct-External-Client", "Authorization": fmt.Sprintf("basic %s", (base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("client:%s", sessionID))))), } req, err := http.NewRequest(http.MethodGet, arsModelsURL, nil) if err != nil { panic(err) } for k, v := range headers { req.Header.Set(k, v) } resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() respBody, err := ioutil.ReadAll(resp.Body) var respParsed map[string]interface{} json.Unmarshal(respBody, &respParsed) fmt.Printf("resp: %s\n", respBody) } // Post func checkIn() (sessionID string, err error) { headers := map[string]string{ "Content-Type": "application/json", // 如果是post请求,需指定content-type "Accept-Type": "application/json", "User-Agent": "QKAct-External-Client", } now := time.Now().Unix() password := fmt.Sprintf("%x", sha256.Sum256([]byte(username))) combineString := fmt.Sprintf("%s%d%s", username, now, password) hashString := fmt.Sprintf("%x", sha256.Sum256([]byte(combineString))) hashPwd := base64.StdEncoding.EncodeToString([]byte(hashString))[:12] body := map[string]string{ "username": username, "timestamp": fmt.Sprintf("%d", now), "passwordHash": hashPwd, "deviceType": "1", "connectionType": "0", } var reqBodyRd io.Reader reqBody, _ := json.Marshal(body) reqBodyRd = bytes.NewReader(reqBody) req, _ := http.NewRequest(http.MethodPost, sessionURL, reqBodyRd) for k, v := range headers { req.Header.Set(k, v) } resp, err := client.Do(req) if err != nil { panic(err) } respBody, err := ioutil.ReadAll(resp.Body) var respParsed map[string]interface{} json.Unmarshal(respBody, &respParsed) fmt.Printf("resp: %v\n", respParsed) for k, v := range respParsed { if k == "sessionID" { return v.(string), nil } } return "", nil }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
2021-03-01 linux的目录系统
2021-03-01 docker容器之实现 nat 转换收发