HTTP请求需检查状态码并关闭响应体,解析JSON应使用结构体而非map,自定义Client设置超时,非UTF-8编码需先转码。

用 http.Get 发起请求并检查状态码
直接调用 http.Get 是最简方式,但必须手动检查 resp.StatusCode,否则 4xx/5xx 响应也会进入后续解码流程,导致 json.Unmarshal 报错或静默失败。
常见错误是忽略 resp.Body 关闭或未读取完就关闭,引发连接复用异常。正确做法是用 defer resp.Body.Close() 并在检查状态后立即读取全部内容:
resp, err := http.Get("https://api.example.com/data")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Fatalf("HTTP %d: %s", resp.StatusCode, resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
用 json.Unmarshal 解析到结构体而非 map[string]interface{}
虽然 json.Unmarshal 支持直接解析到 map[string]interface{},但实际开发中几乎总是应该定义结构体。原因有三:类型安全、字段可读性、IDE 自动补全支持;更重要的是,map[string]interface{} 在嵌套层级稍深时极易因类型断言出错(比如把 float64 当 int 用)。
结构体字段需导出(首字母大写),且推荐使用 json tag 显式声明键名,避免大小写或下划线不一致问题:
立即学习“go语言免费学习笔记(深入)”;
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
}
var u User
if err := json.Unmarshal(body, &u); err != nil {
log.Fatal(err)
}
处理 HTTP 超时和重试逻辑不能只靠 http.DefaultClient
http.DefaultClient 默认无超时,网络卡住时 goroutine 会长时间阻塞。必须自定义 http.Client 并设置 Timeout 或更精细的 Transport 参数。
简单超时可用:
client := &http.Client{
Timeout: 10 * time.Second,
}
resp, err := client.Get("https://api.example.com/data")
若需重试(如临时 502),不要手写 for 循环重试整个请求——应使用带指数退避的库(如 github.com/hashicorp/go-retryablehttp),或至少确保重试前重新创建 req 对象,避免复用已关闭的 body。
中文乱码或非 UTF-8 编码 JSON 怎么办
部分 API 返回的 JSON 声明了 Content-Type: application/json; charset=gbk,但 Go 的 json 包只认 UTF-8。此时不能跳过编码转换,否则 Unmarshal 会报 invalid character。
先用 http.Header.Get("Content-Type") 提取 charset,再用 golang.org/x/text/encoding 系列包转码。例如 GBK:
import "golang.org/x/text/encoding/gbk"decoder := gbk.NewDecoder() body, err := decoder.Bytes(body) if err != nil { log.Fatal(err) } // 再传给 json.Unmarshal
注意:不是所有接口都严格遵守 charset 声明,有些返回 UTF-8 却谎报 GBK,需要结合响应内容试探判断——这点容易被忽略,调试时建议先用 fmt.Printf("%q", body[:min(100, len(body))]) 看原始字节。










