应调用c.xml()而非c.json(),结构体字段必须添加xml tag(如xml:"name"),禁用map直接传参,header自动设为application/xml;若需json/xml共存,需同时声明json:"name" xml:"name"。

如何让 Gin 返回 XML 而不是 JSON
Gin 默认所有 c.JSON() 都走 JSON 编码,要返回 XML 必须显式调用 c.XML(),且结构体需带 xml tag。常见错误是只改了方法但忘了加 tag,结果返回空对象或字段全丢。
实操建议:
- 结构体字段必须标注
xmltag,例如type User struct { Name string `xml:"name"` } - 顶层结构体不能是 map(
c.XML(200, map[string]string{"a": "b"})会 panic),得用 struct 或指针 - HTTP Header 自动设为
Content-Type: application/xml; charset=utf-8,无需手动c.Header() - 如果字段值为空字符串、零值或 nil,对应 XML 元素默认仍会输出(除非加
omitempty)
YAML 响应需要额外引入 github.com/ghodss/yaml
Gin 内置不支持 YAML,必须自己注册 ginsupport.YAML 或直接用第三方库封装。官方没提供 c.YAML(),强行调用会报 undefined 错误。
实操建议:
- 导入
github.com/ghodss/yaml(轻量、兼容标准encoding/json接口) - 写一个中间件或工具函数,例如:
func YAML(c *gin.Context, code int, obj interface{}) { c.Header("Content-Type", "application/yaml; charset=utf-8") data, _ := yaml.Marshal(obj) c.Data(code, "application/yaml; charset=utf-8", data) } - 注意
yaml.Marshal()不处理私有字段(首字母小写),和 JSON 行为一致 - 某些嵌套 map[int]interface{} 场景下,
ghodss/yaml可能比gopkg.in/yaml.v2更稳定
根据 Accept 头自动切换格式的坑
想实现「客户端说要 XML 就给 XML,要 YAML 就给 YAML」,不能只靠 c.Negotiate() —— 它只内置支持 JSON、HTML、PROTBUF,XML 和 YAML 都不在白名单里。
实操建议:
- 手动解析
c.GetHeader("Accept"),用 strings.Contains 判断是否含application/xml或application/yaml - 避免用正则匹配 Accept,简单子串检查更可靠(如
strings.Contains(accept, "application/xml")) - 记得 fallback:没匹配到就走 JSON,否则 406 Not Acceptable 容易被忽略
- 不要在 Negotiate 中传入未注册的 MIME 类型,否则
c.Negotiate(200, gin.NegotiateConfig{...})会静默失败
struct tag 冲突:json 和 xml 共存时怎么写
同一个结构体既要支持 JSON 又要支持 XML,tag 写法稍有不慎就会导致某一种格式字段丢失或命名错乱。
实操建议:
- 同时写
json和xmltag,顺序无关,例如:Name string `json:"name" xml:"name"` - 如果 JSON 要 snake_case、XML 要 camelCase,就分别写:
CreatedAt time.Time `json:"created_at" xml:"createdAt"` - 慎用
omitempty:XML 的 omitempty 行为和 JSON 不完全一致(比如空字符串在 XML 中仍可能被序列化) - 嵌套 struct 指针字段在 XML 中若为 nil,对应标签默认不出现;JSON 中若没写
omitempty,会输出 null —— 这个差异容易引发前端解析异常
c.Negotiate() 实际不支持 XML/YAML 这一事实。











