

新闻资讯
技术学院本文详解go中使用`json.marshal`时因结构体字段标签(struct tag)书写错误(如误用`json:":"text"`)导致json生成异常的问题,并提供正确写法、完整修复示例及关键注意事项。
在使用 Martini(或任何 Go Web 框架)返回 JSON 数据时,若结构体字段的 JSON 标签(json tag)语法不合法,json.Marshal 将无法正确映射字段名,轻则字段丢失、键名异常(如出现 ":" 这类非法键),重则整个字段被忽略,最终输出空对象 {} 或格式错乱的 JSON 字符串——这正是你遇到 "{}{}{}..." 和 {"time":"...","": "Привет"} 等问题的根本原因。
Go 中结构体字段的 JSON 标签必须严格遵循以下格式:
FieldName Type `json:"key_name[,option]"`
其中:
❌ 错误示例(全部失效):
Text string `json:":"text"` // ❌ 冒号位置错误,标签解析失败 User1 string `json:":"user1"` // ❌ 同上
✅ 正确写法:
Text string `json:"text"` User1 string `json:"user1"` Time string `json:"time"`
以下是修正后的可运行代码片段,已整合数据库查询、结构体定义与 JSON 序列化逻辑:
type ChatMessage struct {
Time string `json:"time"`
Text string `json:"text"`
User1 string `json:"user1"`
}
func getChatData() string {
db, err := sql.Open("sqlite3", "./database.db")
if err != nil {
log.Fatal("DB open failed:", err)
}
defer db.Close()
rows, err := db.Query("SELECT time, text, user1 FROM messages")
if err != nil {
log.Fatal("Query failed:", err)
}
defer rows.Close()
var buffer bytes.Buffer
buffer.WriteByte('[') // 开始 JSON 数组
first := true
for rows.Next() {
var time, text, user1 string
if err := rows.Scan(&time, &text, &user1); err != nil {
log.Printf("Scan error: %v", err)
continue // 跳过单条错误,避免中断整个响应
}
msg := ChatMessage{
Time: time, Text: text, User1: user1}
data, err := json.Marshal(msg)
if err != nil {
log.Printf("JSON marshal error: %v", err)
continue
}
if !first {
buffer.WriteByte(',')
}
buffer.Write(data)
first = false
}
buffer.WriteByte(']') // 结束 JSON 数组
return buffer.String()
}? 关键改进说明:使用 []byte 拼接更高效(bytes.Buffer 已优化);手动构造 JSON 数组 [...],确保前端接收的是合法、可解析的 JSON 数组(而非多个独立 JSON 对象拼接,后者不是标准 JSON);添加错误处理与日志提示,避免 log.Fatal 导致服务崩溃;字段名显式赋值(Time: time),提升可读性与可维护性。
通过修正结构体标签语法并采用规范的 JSON 构建方式,你的 API 将稳定输出符合标准的 JSON 数据,彻底解决 {"": "..."} 或 {} 等异常现象。