
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 <p>这会把 <code>á</code> 的两个字节 <code>0xC3 0xA1</code> 分别当作独立字节转成 `<code>(无效 UTF-8),导致输出</code>záÅit<code>这类乱码——这正是你截图中</code>"...+2 more"` 的来源(调试器截断了不完整的 UTF-8 序列)。</p><h3>✅ 正确做法:始终用 <code>range</code> 遍历字符串</h3><p><code>range</code> 在 Go 中自动按 <strong>rune(Unicode 码点)</strong> 迭代字符串,安全且语义清晰:</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill8483" title="dmap-jsapi-skill"><img src="https://img.php.cn/upload/skill/000/000/081/179206214475645.jpg" alt="dmap-jsapi-skill" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill8483" title="dmap-jsapi-skill" class="overflowclass">dmap-jsapi-skill</a> <p class="overflowclass">DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。</p> </div> <a rel="nofollow" href="/xiazai/skill8483" title="dmap-jsapi-skill" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div><pre class="brush:php;toolbar:false;">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 字符串。










