最简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": []string{"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.Get和http.PostForm只是http.DefaultClient的快捷封装。一旦涉及超时、重定向控制、Cookie管理或自定义User-Agent,就得显式构造http.Client。
-
Timeout字段只控制整个请求生命周期(DNS + 连接 + 写请求 + 读响应),不是单独的连接超时 - 若要细粒度控制(如连接超时500ms、读超时2s),得用
http.Transport配置DialContext和ResponseHeaderTimeout - 设置
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客户端。这两点不解决,其他功能再全也没用。










