Go 中自定义错误类型的 JSON 序列化实践
发布时间 - 2026-01-21 00:00:00 点击率:次在 go 的 json api 开发中,直接将实现了 `error` 接口的结构体序列化为 {"error": "message"} 形式需手动实现 json.marshaler,因为标准 json.marshal 无法自动提取未导出字段或 error 接口的底层字符串。
Go 的 encoding/json 包在序列化时依赖反射(reflection),而绝大多数 error 类型(如 errors.New 返回的 *errors.errorString)内部字段是非导出的(unexported),因此默认无法被 JSON 编码器访问。你最初尝试的嵌入 Err error 字段的方式之所以输出 {"error":{}},是因为 json 包对空接口或未导出字段仅能序列化为空对象 {},而非其字符串表示。
要实现预期的 JSON 错误格式,最简洁可靠的方式是让自定义错误类型显式实现 json.Marshaler 接口:
type JsonErr struct {
error // 匿名嵌入,复用 Error() 方法
}
func (e JsonErr) MarshalJSON() ([]byte, error) {
// 注意:需对 error 消息做 JSON 字符串转义,避免注入非法字符(如换行、引号)
msg := strings.ReplaceAll(e.Error(), `"`, `\"`)
msg = strings.ReplaceAll(msg, `\`, `\\`)
msg = strings.ReplaceAll(msg, `\n`, `\\n`)
msg = strings.ReplaceAll(msg, `\r`, `\\r`)
msg = strings.ReplaceAll(msg, `\t`, `\\t`)
return []byte(`{"error": "` + msg + `"}`), nil
}⚠️ 更安全、推荐的做法是使用 json.Marshal 对消息本身进行转义,而非手动替换:
func (e JsonErr) MarshalJSON() ([]byte, error) {
type Alias JsonErr // 防止递归调用 MarshalJSON
data := struct {
Error string `json:"error"`
}{
Error: e.Error(),
}
return json.Marshal(data)
}该方案利用了匿名结构体+内嵌别名技巧,既避免了无限递归(因 Alias 不再实现 MarshalJSON),又借助标准库完成完整的 JSON 转义与格式化,语义清晰且健壮。
✅ 使用示例:
err := JsonErr{errors.New(`Invalid request
: "user_id" is missing`)}
b, _ := json.Marshal(err)
fmt.Println(string(b)) // 输出:{"error":"Invalid request: \"user_id\" is missing"}? 补充建议:
- 在真实 API 中,可扩展 JsonErr 为包含 Code int、Message string、Details map[string]interface{} 等字段的结构,统一错误响应规范;
- 始终优先使用 json.Marshal 处理字符串内容,避免手拼 JSON——它能正确处理 Unicode、控制字符和引号转义;
- 若需全局错误处理(如 HTTP 中间件),可结合 http.Error 或自定义 ErrorResponse 类型统一序列化逻辑。
通过实现 MarshalJSON,你既能保持 error 接口的兼容性,又能精准控制其 JSON 表现形式,是构建健壮、可维护 Go Web API 的关键实践之一。
# js
# json
# go
# 编码
# ai
# 标准库
# 中间件
# String
# Error
# 字符串
# 结构体
# 递归
# int
# 接口
# Interface
# Reflection
# map
# 对象
# http
# 自定义
# 序列化
# 而非
# 是因为
# 又能
# 它能
# 仅能
# 既能
# 表现形式
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
QQ浏览器网页版登录入口 个人中心在线进入
Javascript中的事件循环是如何工作的_如何利用Javascript事件循环优化异步代码?
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?
Laravel如何实现API版本控制_Laravel版本化API设计方案
Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置
如何基于云服务器快速搭建网站及云盘系统?
EditPlus中的正则表达式实战(5)
齐河建站公司:营销型网站建设与SEO优化双核驱动策略
如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体
济南网站建设制作公司,室内设计网站一般都有哪些功能?
Laravel任务队列怎么用_Laravel Queues异步处理任务提升应用性能
Thinkphp 中 distinct 的用法解析
Laravel Sail是什么_基于Docker的Laravel本地开发环境Sail入门
Laravel请求验证怎么写_Laravel Validator自定义表单验证规则教程
实例解析Array和String方法
如何快速登录WAP自助建站平台?
如何在云指建站中生成FTP站点?
Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】
,怎么在广州志愿者网站注册?
如何自定义建站之星网站的导航菜单样式?
Laravel如何保护应用免受CSRF攻击?(原理和示例)
Laravel辅助函数有哪些_Laravel Helpers常用助手函数大全
php静态变量怎么调试_php静态变量作用域调试技巧【解答】
Laravel如何配置Horizon来管理队列?(安装和使用)
如何为不同团队 ID 动态生成多个非值班状态按钮
绝密ChatGPT指令:手把手教你生成HR无法拒绝的求职信
Laravel集合Collection怎么用_Laravel集合常用函数详解
详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)
微信h5制作网站有哪些,免费微信H5页面制作工具?
php打包exe后无法访问网络共享_共享权限设置方法【教程】
Laravel怎么配置不同环境的数据库_Laravel本地测试与生产环境动态切换【方法】
Laravel如何获取当前用户信息_Laravel Auth门面获取用户ID
武汉网站设计制作公司,武汉有哪些比较大的同城网站或论坛,就是里面都是武汉人的?
黑客如何通过漏洞一步步攻陷网站服务器?
网站制作大概要多少钱一个,做一个平台网站大概多少钱?
Laravel中的withCount方法怎么高效统计关联模型数量
Laravel Seeder怎么填充数据_Laravel数据库填充器的使用方法与技巧
Laravel怎么实现搜索功能_Laravel使用Eloquent实现模糊查询与多条件搜索【实例】
厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?
Laravel如何实现本地化和多语言支持?(i18n教程)
INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】
html5的keygen标签为什么废弃_替代方案说明【解答】
制作旅游网站html,怎样注册旅游网站?
如何挑选最适合建站的高性能VPS主机?
Laravel如何为API编写文档_Laravel API文档生成与维护方法
JavaScript模板引擎Template.js使用详解
Laravel事件监听器怎么写_Laravel Event和Listener使用教程
html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】
油猴 教程,油猴搜脚本为什么会网页无法显示?


