
本文详解 go 中通过实现 `marshaljson()` 方法或使用结构体标签(struct tags)来自定义 json 序列化行为,纠正常见手动拼接导致的非法 json 错误,并提供可直接运行的最佳实践示例。
在 Go 中自定义 JSON 编码输出主要有两种方式:结构体字段导出 + JSON 标签控制(推荐默认方案),以及手动实现 json.Marshaler 接口(适用于复杂逻辑)。你遇到的错误:
json: error calling MarshalJSON for type main.Info: invalid character 'o' in literal false (expecting 'a')
根本原因是手动拼接的字符串不符合 JSON 语法规范——例如 "false" 是字符串字面量,而合法的布尔值应为 false(不带引号);同时缺失对象起始 {、字段名、冒号、逗号分隔及结尾 },导致生成了类似 foo"false" 这样的非法片段。
✅ 正确实现 MarshalJSON() 的写法
若确实需要自定义逻辑(如动态字段、加密字段、格式转换等),必须生成严格符合 RFC 8259 的 JSON 字符串。以下是修复后的完整示例:
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
)
type Info struct {
name string
flag bool
}
func (i Info) MarshalJSON() ([]byte, error) {
var b bytes.Buffer
b.WriteString(`{"name":"`) // 字段名和字符串值均需双引号包裹
b.WriteString(i.name)
b.WriteString(`","flag":`) // 注意冒号后无空格(也可加,但需保持一致)
if i.flag {
b.WriteString("true") // 布尔值不加引号!
} else {
b.WriteString("false")
}
b.WriteString(`}`) // 闭合 JSON 对象
return b.Bytes(), nil
}
func main() {
a := []Info{
{"foo", true},
{"bar", false},
}
out, err := json.Marshal(a)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(out))
// 输出: [{"name":"foo","flag":true},{"name":"bar","flag":false}]
}⚠️ 注意事项:
自定义设置的程度更高可以满足大部分中小型企业的建站需求,同时修正了上一版中发现的BUG,优化了核心的代码占用的服务器资源更少,执行速度比上一版更快 主要的特色功能如下: 1)特色的菜单设置功能,菜单设置分为顶部菜单和底部菜单,每一项都可以进行更名、选择是否隐 藏,排序等。 2)增加企业基本信息设置功能,输入的企业信息可以在网页底部的醒目位置看到。 3)增加了在线编辑功能,输入产品信息,企业介绍等栏
- 手动拼接易出错,务必确保:字段名双引号、字符串值双引号、布尔/数字/null 不加引号、对象用 {} 包裹、数组用 [] 包裹、键值间用 :、成员间用 , 分隔;
- 建议优先使用 json.RawMessage 或预构建 map[string]interface{} 辅助构造,而非纯字节拼接;
- 若需处理嵌套、递归或引用,务必调用 json.Marshal() 递归序列化子值,避免自行解析类型。
✅ 更简洁、安全、推荐的方式:使用导出字段 + JSON 标签
绝大多数场景下,无需手动实现 MarshalJSON()。只需将结构体字段首字母大写(使其可导出),并配合 json struct tag 控制键名与行为:
type Info struct {
Name string `json:"name"` // 序列化为小写 "name"
Flag bool `json:"flag"` // 序列化为小写 "flag"
// 可选:忽略空值
// Age int `json:"age,omitempty"`
// 显式忽略字段
// ID int `json:"-"`
}此时 json.Marshal() 会自动完成标准序列化,且支持反序列化(Unmarshal)、omitempty、string 类型转换(如 time.Time)等高级特性。
? 补充:常用 JSON 标签选项
| Tag 示例 | 说明 |
|---|---|
| `json:"name"` | 指定 JSON 键名为 name | |
| `json:"name,omitempty"` | 当字段为零值时省略该字段(对 string/int/bool/slice/map 有效) | |
| `json:"-"` | 完全忽略该字段(不参与编解码) |
| `json:"name,string"` | 将数值类型(如 int)编码为 JSON 字符串(如 123 → "123") |
✅ 总结
- ❌ 避免手动拼接非法 JSON 字符串(如 "false" 代替 false);
- ✅ 优先使用导出字段 + json tag,简洁、安全、可逆;
- ✅ 仅在需动态逻辑(如按环境过滤字段、加密敏感值、兼容旧协议)时才实现 MarshalJSON(),且务必使用 json.Marshal() 递归处理子结构;
- ? 参考官方文档:encoding/json — Marshal 与 Struct Tags。
遵循以上原则,即可高效、可靠地定制 Go 中的 JSON 输出格式。









