SpringBoot响应Content-Type编码差异致移动端字符乱码问题咨询
SpringBoot 2.6.3 JSON响应编码差异问题说明
测试场景基础信息
后端服务采用SpringBoot 2.6.3版本搭建,测试请求统一为GET * HTTP/1.1,请求头携带Accept: */*,服务端响应的Content-Type存在两种取值:application/json、application/json;charset=UTF-8,不同客户端表现差异如下:
- 移动端Chrome、Safari浏览器场景:
- 响应
Content-Type为application/json时,韩文等非ASCII字符出现编码乱码 - 响应
Content-Type为application/json;charset=UTF-8时,所有字符显示无异常
- 响应
- PC端Chrome浏览器场景:
- 无论服务端返回上述哪种
Content-Type,韩文等非ASCII字符均无乱码问题
- 无论服务端返回上述哪种
问题1:两种Content-Type的核心差异,携带charset=UTF-8无乱码的原因
按照RFC对MIME类型的定义,application/json的默认字符集确实是UTF-8,但这个规范的落地程度在不同客户端上天差地别:
- 响应头不带
charset=UTF-8时,客户端拿不到服务端明确给出的解码规则,只能用自身预设的默认编码解析响应体。大部分移动端浏览器的兼容逻辑做的很精简,不会主动给application/json类型默认套用UTF-8编码,反而会优先用WebView内置的默认编码(比如部分旧安卓WebView默认用GBK、旧iOS WebView默认用ISO-8859-1)解析,非ASCII字符和编码规则不匹配,自然就出乱码。 - 响应头带上
charset=UTF-8时,相当于服务端给了客户端明确的解码指令,所有遵循HTTP基础协议的客户端都会优先读取这个参数指定的编码解析内容,不会乱猜编码,自然不会出现编码不匹配的问题。
顺带提下SpringBoot 2.6.3的默认逻辑:这个版本内置的Jackson做JSON序列化时,默认返回的Content-Type就是不带charset参数的application/json,要全局补上charset参数,要么在配置文件中设置server.servlet.encoding.charset=UTF-8并开启强制编码输出,要么自定义MappingJackson2HttpMessageConverter,手动给JSON响应的Content-Type拼接上charset参数即可。
问题2:PC端Chrome不受charset参数影响、无乱码的原因
核心原因是PC端Chrome的编码兼容兜底逻辑做的足够重:
- 它内置了完整的RFC规范映射表,只要识别到响应类型是
application/json,就算响应头没带charset参数,也会默认用UTF-8解码,不会随便调用系统默认编码。 - 它自带成熟的编码自动嗅探能力,就算初始解码选错了编码,也会扫描响应体的字节特征,自动识别出内容实际使用的编码格式,动态切换解码规则,不会把乱码直接展示给用户。
移动端浏览器受限于安装包体积、运行性能限制,基本都砍掉了这套复杂的编码嗅探逻辑,也没有完全对齐所有RFC规范的默认值,才会出现必须显式声明charset才能正常显示非ASCII字符的情况。
内容的提问来源于stack exchange,提问作者이동옥
相关产品推荐
相关产品推荐

