
Go 的 json.Decoder 原生支持 UTF-8,但错误地按字节遍历字符串(如 for i := 0; igo 的 `json.decoder` 原生支持 utf-8,但错误地按字节遍历字符串(如 `for i := 0; i
在 Go 中解析含非 ASCII 字符(如
"zářit")的 JSON 数据时,解码本身是正确的——json.Decode()已完整、准确地将 UTF-8 编码的 JSON 字符串还原为 Go 的string类型(底层为 UTF-8 字节序列)。问题并非出在解码环节,而是后续对string的错误遍历方式引发的显示/处理异常。? 根本原因:
len(string)返回字节数,而非字符数Go 中
string是只读字节切片,len(s)返回其 UTF-8 编码后的字节数,而非 Unicode 码点(rune)数量。例如:s := "zářit" fmt.Println(len(s)) // 输出: 7 → 因为 'á' (U+00E1) 和 'ř' (U+0159) 各占 2 字节,共 5 个字符 → 7 字节 fmt.Println(len([]rune(s))) // 输出: 5 → 正确的 Unicode 字符数当你执行:
for i := 0; i < len(request.Arg); i++ { char := request.Arg[i] // ❌ 错误:取的是第 i 个字节,不是第 i 个字符! fmt.Print(string(char)) }这会把
á的两个字节0xC3 0xA1分别当作独立字节转成 `(无效 UTF-8),导致输出záÅit这类乱码——这正是你截图中"...+2 more"` 的来源(调试器截断了不完整的 UTF-8 序列)。✅ 正确做法:始终用
range遍历字符串
range在 Go 中自动按 rune(Unicode 码点) 迭代字符串,安全且语义清晰:
dmap-jsapi-skill下载DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
request := Request{Arg: "zářit"} fmt.Println("Correct iteration with range:") for i, r := range request.Arg { fmt.Printf("Index %d: rune %U ('%c')\n", i, r, r) } // 输出: // Index 0: rune U+007A ('z') // Index 1: rune U+00E1 ('á') // Index 2: rune U+0159 ('ř') // Index 3: rune U+0069 ('i') // Index 4: rune U+0074 ('t')? 注意:
i是 rune 在字符串中的起始字节索引(非序号),r才是真正的 Unicode 字符。?️ 网络通信场景下的关键修正(你的原始 socket 代码)
你原始的 socket 读取逻辑存在两个隐患:
- 未处理粘包与不完整 JSON:
conn.Read(buf)可能只读到部分 JSON,或一次读到多个消息;- 未清理缓冲区尾部零值:
buf全局分配,buf[:]包含未读取的零字节,string(buf[:])会将\x00视为有效内容,破坏 JSON 结构。✅ 推荐修复方案(健壮 + UTF-8 安全):
// ✅ 正确的 socket JSON 读取与解码 func handleConnection(conn net.Conn) { defer conn.Close() // 使用 bufio.Scanner 按行或按 JSON 对象边界读取(推荐) scanner := bufio.NewScanner(conn) for scanner.Scan() { rawJSON := scanner.Bytes() // []byte,无零填充风险 var req Request if err := json.Unmarshal(rawJSON, &req); err != nil { log.Printf("Invalid JSON: %v → %s", err, rawJSON) continue } // ✅ req.Arg 现在是正确 UTF-8 string,可安全 range 遍历 fmt.Printf("Received: %s\n", req.Arg) for _, r := range req.Arg { fmt.Printf("%c", r) // 正确输出每个字符 } fmt.Println() } }⚠️ 注意事项总结
json.Unmarshal/json.Decoder完全支持 UTF-8,无需额外配置;- 绝对避免
for i := 0; i 处理含非 ASCII 的字符串;- 调试时用
fmt.Printf("%q", s)查看原始转义(如"zářit"→"z\u00e1\u0159it"),比直接println更可靠;- 网络传输中确保客户端(.NET Core)也以 UTF-8 编码发送 JSON(默认即如此,但需确认
HttpClient或WebSocket未误设编码);- 如需字节级操作(如计算 UTF-8 长度),用
utf8.RuneCountInString(s)替代len(s)。遵循以上原则,你的 Go 服务即可无缝、可靠地处理全球任意语言的 UTF-8 JSON 字符串。


















