在 go 构建 json api 时,需将错误以标准 json 格式(如 {"error": "message"})返回;直接嵌入 error 字段无法自动序列化,须显式实现 json.marshaler 接口。
要让自定义错误类型(如 JsonErr)在调用 json.Marshal 或 json.NewEncoder.Encode 时输出结构化的 JSON 错误响应,关键在于正确实现 json.Marshaler 接口,而非依赖 error 接口本身——因为 encoding/json 包不会对 error 类型做特殊处理,且大多数 error 实现(如 errors.New 返回的 *errors.errorString)内部字段非导出,反射无法访问。
推荐做法是采用内嵌 error 接口 + 自定义 MarshalJSON() 方法的方式,简洁且符合 Go 惯例:
type JsonErr struct {
error // 内嵌 error,自动获得 Error() 方法
}
func (e JsonErr) MarshalJSON() ([]byte, error) {
// 安全转义错误消息,避免 JSON 注入(生产环境务必使用)
msg := strings.ReplaceAll(e.Error(), `"`, `\"`)
return []byte(`{"error": "` + msg + `"}`), nil
}⚠️ 注意:上述字符串拼接仅作演示,实际项目中应使用 json.Marshal 处理消息字段以确保 JSON 安全性:
func (e JsonErr) MarshalJSON() ([]byte, error) {
type Alias JsonErr // 防止无限递归(避免再次调用本方法)
return json.Marshal(struct {
Error string `json:"error"`
}{
Error: e.Error(),
})
}这样既保持了类型清晰,又

func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(JsonErr{errors.New("Invalid request syntax")})
}
// 输出:{"error": "Invalid request syntax"}✅ 总结: