HTTP handler中直接return error编译报错,应定义带状态码的AppError类型并统一处理;json.Encode需显式检查err避免panic;recover后须先WriteHeader再写body;生产环境错误信息需脱敏。

HTTP handler里直接return error会丢掉状态码
Go 的 http.Handler 接口不接受 error 返回值,你写 return err 编译就报错。常见错误是把业务逻辑里的 err != nil 一判断,就直接 http.Error(w, err.Error(), http.StatusInternalServerError) —— 这样看似简单,但所有错误都变成 500,前端无法区分是参数错(400)、未登录(401)、没权限(403)还是服务炸了(500)。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 定义统一错误类型,比如
type AppError struct { Code int; Msg string; Err error },带 HTTP 状态码字段 - handler 中用
if err != nil { handleError(w, err) },而不是裸调http.Error -
handleError函数内部做类型断言:if appErr, ok := err.(*AppError); ok { http.Error(w, appErr.Msg, appErr.Code) },否则 fallback 到 500
json.Marshal 失败导致 panic 而不是返回 500
很多新手在 handler 末尾写 json.NewEncoder(w).Encode(resp),结果 resp 里有 time.Time 字段没实现 json.Marshaler,或含 nil map/slice,运行时 panic,HTTP 连接直接断开,日志里只留一行 goroutine crash,前端收不到任何响应。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 永远用
err := json.NewEncoder(w).Encode(resp)显式检查err - 如果
err != nil,先w.WriteHeader(http.StatusInternalServerError),再写错误体,避免 header 已发送后又尝试写 body - 对输出结构体加
//go:generate go run golang.org/x/tools/cmd/stringer -type=StatusCode类型约束,或用encoding/json的MarshalJSON方法预检字段
中间件里 recover 捕获 panic 后忘记设置 status code
用了 defer func() { if r := recover(); r != nil { /* log */ } }() 做兜底,但忘了 w.WriteHeader(http.StatusInternalServerError),结果默认 200 + 空 body,前端以为成功了。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- recover 后第一件事是
w.WriteHeader(http.StatusInternalServerError),哪怕后面还要写 JSON 错误体 - 不要在 recover 里直接调
http.Error,它内部会覆盖已写的 header;先设 status,再手动写 body - 配合
http.Hijacker或ResponseWriter包装器记录是否已写 header,避免重复 WriteHeader 报 warning
error message 泄露敏感信息或内部路径
开发环境直接把 err.Error() 返回给前端,比如 "failed to connect to postgres://xxx@127.0.0.1:5432: dial tcp 127.0.0.1:5432: connect: connection refused",暴露数据库地址、端口甚至连接串片段。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 生产环境 error body 只返回泛化提示,如
"service unavailable",详细日志打到zap或logrus并带上 traceID - 用
errors.Is(err, os.ErrNotExist)或自定义 sentinel error(如var ErrUserNotFound = errors.New("user not found"))做分类,不同类别映射不同用户提示 - 所有对外输出的 error message 必须经过
sanitizeError函数过滤,移除@、://、IP、路径等模式
事情说清了就结束。最常被忽略的是:错误类型必须可判断、可分类、可控制输出,而不是靠字符串匹配或层层 if-else。










