信息发布→ 登录 注册 退出

Golang HTTP服务中错误返回的标准方式

发布时间:2026-01-08

点击量:
HTTP handler 中不能 return 错误,须手动调用 w.WriteHeader() 和 w.Write() 发送响应;应封装 writeError 工具函数统一处理 JSON 错误格式,并用 recover 中间件兜底 panic,严格区分 4xx 与 5xx 状态码。

HTTP handler 中直接 return 错误不生效

Go 的 http.HandlerFunc 返回类型是 void,没有返回值接口,所以写 return err 是语法错误。常见误区是以为能像其他语言那样“抛出异常”或“中断流程”,实际必须手动调用 w.WriteHeader() + w.Write() 才算完成响应。

正确做法是:在出错时立即写入状态码和响应体,并避免后续逻辑继续执行(比如不要在 if err != nil 后面还调用 json.NewEncoder(w).Encode(...))。

  • 状态码优先用标准常量:http.StatusBadRequesthttp.StatusNotFoundhttp.StatusInternalServerError
  • 响应体建议统一 JSON 格式,包含 error 字段,例如:{"error": "invalid ID format"}
  • 不要忘记在写完响应后 return,防止后续代码意外写入已关闭的 ResponseWriter

封装统一的 error response 工具函数

重复写 w.WriteHeader() + json.Marshal() + w.Write() 容易遗漏或不一致。推荐封装一个 writeError(w http.ResponseWriter, status int, msg string) 函数,集中控制格式和 Content-Type。

注意点:

  • 务必先设置 w.Header().Set("Content-Type", "application/json; charset=utf-8"),否则前端可能解析失败
  • 状态码要在 w.Write() 前调用 w.WriteHeader(status);如果已经写过响应体,再调用会静默忽略
  • 避免在工具函数里 panic 或 log.Fatal —— 这会让整个服务崩溃
func writeError(w http.ResponseWriter, status int, msg string) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(map[string]string{"error": msg})
}

中间件中拦截 panic 并转为 500 错误

未捕获的 panic 会导致连接被关闭,客户端收不到任何响应。生产环境必须用中间件兜底:

  • defer/recover 捕获 handler 内 panic
  • 恢复后仍要调用 w.WriteHeader(http.StatusInternalServerError),否则默认是 200
  • 日志中记录 panic stack,但响应体不要暴露敏感信息(如文件路径、变量值)
func recoverMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				log.Printf("PANIC in %s %s: %v", r.Method, r.URL.Path, err)
				w.Header().Set("Content-Type", "application/json; charset=utf-8")
				w.WriteHeader(http.StatusInternalServerError)
				json.NewEncoder(w).Encode(map[string]string{"error": "internal server error"})
			}
		}()
		next.ServeHTTP(w, r)
	})
}

区分客户端错误与服务端错误,别滥用 500

4xx 错误(如 http.StatusBadRequesthttp.StatusUnauthorized)表示请求本身有问题,应由客户端修正;5xx 表示服务内部故障,需要后端排查。混用会导致监控失真、重试策略失效。

典型场景判断:

  • JSON 解析失败、字段缺失、ID 格式错误 → http.StatusBadRequest
  • 数据库连接失败、下游服务超时、空指针解引用 → http.StatusInternalServerError
  • JWT 过期或签名无效 → http.StatusUnauthorized(不是 403)
  • 资源不存在(如 GET /users/9999)→ http.StatusNotFound,而非 500

最常被忽略的是:没查到数据就直接返回空 JSON 或 200,掩盖了业务语义上的“不存在”。该 404 就得 404。

标签:# 不存在  # void  # 指针  # 接口  # 空指针  # nil  # 数据库  # http  # 客户端  # int  # 的是  # 集中控制  # 要在  # 就得  # 而非  # 才算  # 这会  # 写完  # 状态码  # 前端  # json  # go  # golang  # app  # 工具  # usb  # 后端  # js  # 中间件  # String  # 常量  # if  # 封装  # format  # Error  
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!