
本文详解 go 中如何正确解码前端传来的 json 对象(如 {"世":1,"界":1}),指出结构体绑定失败的根本原因,并提供直接解码为 map[string]int 的简洁方案,同时说明如何安全地将数据以 json 格式响应给前端。
你遇到的问题非常典型:前端调用 JSON.stringify({ "世": 1, "界": 1, "最": 1, "強": 1 }) 发送的是一个顶层 JSON 对象(object),而非包含该对象的 JSON 结构体数组或包装对象。而你的 Go 结构体:
type text struct {
Text map[string]int
}期望接收到的 JSON 形如:
{ "Text": { "世": 1, "界": 1, "最": 1, "強": 1 } }但实际收到的是:
{ "世": 1, "界": 1, "最": 1, "強": 1 }——二者 JSON 结构不匹配,导致 json.Decode(&t) 静默失败(字段未填充),最终 t.Text 为 nil,日志输出 map[]。
立即学习“前端免费学习笔记(深入)”;
✅ 正确做法是:跳过结构体,直接解码为 map[string]int,因为它与原始 JSON 的顶层结构完全一致:
func PostHandler(w http.ResponseWriter, r *http.Request) {
log.Println("post start")
if r.Method != "POST" {
http.NotFound(w, r)
return
}
decoder := json.NewDecoder(r.Body)
var data map[string]int // 直接对应 {"key": value} 的 JSON object
if err := decoder.Decode(&data); err != nil {
log.Printf("JSON decode error: %v", err)
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
log.Printf("Decoded: %+v", data) // 输出 map[世:1 界:1 最:1 強:1]
// ✅ 正确返回 JSON 给前端:使用 json.Marshal + 设置 Content-Type
w.Header().Set("Content-Type", "application/json; charset=utf-8")
if err := json.NewEncoder(w).Encode(data); err != nil {
log.Printf("JSON encode error: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
}? 关键要点说明:
- 不要强制套用结构体:当 JSON 是扁平对象且无固定字段名时(如动态键名的词频映射),map[string]T 是最自然、最安全的选择;
- 避免 w.Write([]byte(t.Text)) 类型错误:map[string]int 不能直接转 []byte,必须经 json.Marshal 或 json.NewEncoder 序列化;
- 务必设置 Content-Type:前端(如 fetch)依赖此头识别响应为 JSON,否则可能解析失败;
- 错误处理不可省略:Decode 和 Encode 均可能失败,应检查 err 并返回恰当 HTTP 状态码(如 400 Bad Request / 500 Internal Server Error);
- UTF-8 支持开箱即用:Go 的 encoding/json 默认支持 Unicode(包括中文键名),无需额外配置。
? 进阶提示:若后续需扩展为带元信息的结构(如添加 timestamp 或 version),可定义结构体并使用 json.RawMessage 延迟解析动态部分,但当前场景保持简单即最优解。










