Golang如何处理HTTP请求与响应_Golang net/http使用详解

1次阅读

go net/http需显式处理资源生命周期:必须Close请求/响应Body、Header设于WriteHeader前、自定义Client设超时;路由用显式ServeMux、jsON用流式解码、响应用json.Encoder。

Golang如何处理HTTP请求与响应_Golang net/http使用详解

Go 的 net/http 包开箱即用,不需要任何第三方依赖就能跑起一个生产级 HTTP 服务或客户端——但“能跑”和“跑稳”之间,差的往往是几行错误处理、一次 Body.Close() 或一个被忽略的 Header() 调用顺序。

怎么注册路由:别只用 http.HandleFunc,优先显式用 http.ServeMux

默认的 http.DefaultServeMux 是全局单例,所有 http.HandleFunc 都往它上面注册。这在小脚本里没问题,但在中大型项目里容易污染、难测试、无法隔离中间件

  • 显式创建 http.ServeMux:更清晰、可复用、支持子路由前缀(比如 http.StripPrefix("/api", apiHandler)
  • 路径匹配是前缀匹配:"/users" 会匹配 /users/123/users?name=alice;而 "/users/"(结尾带斜杠)才表示“子路径模式”
  • 不支持通配符(如 /users/{id}),需要自己解析 r.URL.Path 或引入路由库

怎么读请求体:别用 io.ReadAll(r.Body) 直接硬读

r.Body 是个 io.ReadCloser,只能读一次,且不关会泄漏连接。对 JSON 请求,json.NewDecoder(r.Body).Decode(&v) 是更省内存、更安全的选择——它流式解析,不把整个请求体加载进内存。

  • 必须 defer r.Body.Close(),哪怕你用 json.NewDecoder —— 它内部不会自动关闭
  • 不要在 decode 前调用 r.ParseForm()r.FormValue(),它们会提前消费 Body,导致后续 decode 失败
  • 若需同时支持表单和 JSON,先检查 r.Header.Get("Content-Type") 再分支处理

怎么写响应体:状态码、头、正文三者有严格时序

w.Header().Set() 必须在 w.WriteHeader() 或第一次 w.Write() 之前调用,否则会被静默忽略。很多“Content-Type 不生效”的问题都源于此。

立即学习go语言免费学习笔记(深入)”;

  • 推荐统一用 json.NewEncoder(w).Encode(v) 输出 JSON:自动处理编码、写入、错误返回,比 json.Marshal + w.Write 更健壮
  • 手动设状态码w.WriteHeader(http.StatusCreated),别依赖默认 200;尤其 POST 成功后应返回 201
  • 设置头信息时,"Content-Type" 推荐带 charset=utf-8,比如 "application/json; charset=utf-8"

怎么发 HTTP 客户端请求:永远别用 http.Get 上生产

http.Get 用的是 http.DefaultClient,没有超时控制。网络卡住时,goroutine 就永远挂起,最终耗尽资源。

  • 必须自定义 *http.Client,至少设 Timeout(例如 10 * time.Second
  • 务必 defer resp.Body.Close(),且要放在 if err == nil 分支内第一行,防止 respnil 时 panic
  • 大响应体建议用 io.LimitReader(resp.Body, maxBytes) 防 OOM,别等 io.ReadAll 把几百 MB 全读进内存

最常被跳过的细节不是语法,而是资源生命周期:r.Body 要关、resp.Body 要关、Header() 要在写之前设、ListenAndServe 的错误必须 log.Fatal 或显式处理——这些地方漏一个,服务就可能在线上安静地掉链子。

text=ZqhQzanResources