Go如何发起GET与POST请求_net http请求示例解析

最简GET请求用http.Get,但需手动Close响应体并检查状态码;POST表单用http.PostForm;超时等高级配置必须用自定义http.Client;POST JSON需设Content-Type并用strings.NewReader。

Go用http.Get发GET请求最简写法

直接调用http.Get就能发起无头信息、无超时控制的GET请求,适合快速测试或内部简单调用。但它默认不设超时,生产环境容易卡死。

  • 必须手动调用resp.Body.Close(),否则连接不会释放,会触发too many open files
  • 响应状态码需自行检查:if resp.StatusCode != http.StatusOK
  • 响应体要读完才能复用底层TCP连接,建议用io.ReadAll(resp.Body)而非只读前几字节
resp, err := http.Get("https://httpbin.org/get")
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close() // 关键!

body, _ := io.ReadAll(resp.Body) fmt.Printf("status: %d, body: %s", resp.StatusCode, string(body))

POST表单数据用http.PostForm最省事

提交application/x-www-form-urlencoded数据(比如登录表单)时,http.PostForm自动设置Header、编码参数,比手拼bytes.NewReader更安全。

  • 第二个参数是url.Values,不是普通map:用url.Values{"key": []string{"value"}}构造
  • 它内部调用http.DefaultClient.Do,仍无超时;如需控制超时,请跳到下节用自定义Client
  • 返回的*http.Response同样要Close(),规则和GET一致
data := url.Values{"username": []st

ring{"admin"}, "password": []string{"123"}} resp, err := http.PostForm("https://httpbin.org/post", data) if err != nil { log.Fatal(err) } defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body) fmt.Println(string(body))

需要超时/重试/自定义Header?必须用http.Client

http.Gethttp.PostForm只是http.DefaultClient的快捷封装。一旦涉及超时、重定向控制、Cookie管理或自定义User-Agent,就得显式构造http.Client

  • Timeout字段只控制整个请求生命周期(DNS + 连接 + 写请求 + 读响应),不是单独的连接超时
  • 若要细粒度控制(如连接超时500ms、读超时2s),得用http.Transport配置DialContextResponseHeaderTimeout
  • 设置Client.CheckRedirect可拦截并修改重定向行为,避免被302带到不可信域名
client := &http.Client{
    Timeout: 5 * time.Second,
}
req, _ := http.NewRequest("POST", "https://httpbin.org/post", strings.NewReader(`{"name":"go"}`))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", "MyApp/1.0")

resp, err := client.Do(req) if err != nil { log.Fatal(err) } defer resp.Body.Close()

POST JSON别忘设Content-Type且用strings.NewReader

Go的http.Post函数第三个参数是io.Reader,不能直接传string[]byte——它不会自动帮你转成Reader。常见错误是写http.Post(url, "application/json", []byte(jsonStr)),这会编译失败。

  • 正确做法:用strings.NewReader(jsonStr)bytes.NewReader([]byte(jsonStr))
  • Content-Type必须显式设置,http.Post不会自动加;漏掉会导致后端解析为text/plain而失败
  • 如果JSON结构复杂,优先用json.Marshal生成字节流,避免手拼字符串出错
jsonStr, _ := json.Marshal(map[string]string{"msg": "hello"})
resp, err := http.Post("https://httpbin.org/post", "application/json", strings.NewReader(string(jsonStr)))
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

实际项目里最容易被忽略的是Body.Close()和超时配置。没关Body,压测时QPS上不去还报错;没设超时,上游服务卡住就拖垮整个HTTP客户端。这两点不解决,其他功能再全也没用。