浏览器的Chart set(UTF8,GBK等)设置对Javascript无效?

qinjianxiang
  • 5.9k
现象
  1. 打开weibo.com
  2. 登录,跳转到首页
  3. 通过浏览器菜单更改编码,观察到:
  4. 当编码设置为UTF8时,整个页面正常;(测试环境:Chrome,Safari)
  5. 当编码设置为GBK / Big5 / Shfit JIS(一种日文编码),除title(浏览器Tab里显示的)和页面底部的文本乱码外,页头及页面主体都正常显示(测试环境:Chrome,Safari)
  6. 当编码设置为ISO 2022-KR(一种韩文编码)时,title和页面底部的文本乱码,页头及页面主体空白(测试环境:Safari)

无论浏览器编码怎么改变,服务端返回的内容都是UTF-8编码

猜测

上述会乱码的title和页面底部都是以UTF8中文写在HTML源码中的,HTML源码由浏览器渲染,故浏览器编码设置不是UTF8时就会乱码。

而页头、页面主体的内容是以utf8串(如\u4e2d\u56fd\u5de5\u5546\u94f6\u884c\u7535\u5b50\u94f6\u884c)的形式写在script标签中,或者从服务端ajax请求得到的

浏览器只负责Javascript语法解析及执行,不负责JS输出中文的编码展示,故,js output里的中文显示跟浏览器的Charset设置无关

求助

1. 上面只是我的猜测,我分别用browser javascript charset render在google上搜索了半天,没找到官方权威的说法来证实我的猜测,求前端专家指点迷津,给个权威的链接。
2. 切换成韩文为什么js也不正常了呢?是韩文编码环境下,script标签里的js语法解析出错了吗?

回复
阅读 15.6k
5 个回答
xuecan
  • 1.9k

打开 Safari 的 Web检查器,切换到 问题 标签。然后修改浏览器的编码设置,会观察到当切换为韩文的时候,加载 .js 会有很多出错信息。而 GBK / Big5 / Shift JIS 不会。因此估计是 ISO 2022-KR 编码“入侵”了 ASCII 的前 127 个字符造成。

Google 了一下,发现韩文编码典型的一个做法是将反斜杠“\”转换为韩元字符“₩”。因此,加载一个充斥着反斜杠的 .js 自然就会出错了。

更新

前面说的不完全正确,因为 Shift JIS 也占用了 \BIG5 也使用了正常 ASCII 字符的编码。进一步观察 Web检查器,发现当编码设置为 GBK / Big5 / Shift JIS,实际加载的 .js 还是 UTF-8 的,而换成 ISO 2022-KR 则不然。这应该是浏览器具体实现的问题。

哈哈,作为微博BigPipe服务端的实现者,我从来没想过诸位会用这么变态的方法测试……

我在chrome下重试了以上的实验,切换各种编码都只是导致页脚乱码,其他区域都正常显示,韩文没有出现头尾乱码页面空白的情况,这个问题可能跟safari对韩文编码的支持有关系。

其实原因前几位都说过了,使用bigpipe是通过回调js的方式做客户端渲染,输出的内容以json编码存在。JSON要求输出unicode,而浏览器中的js引擎负责将unicode字符转换成页面对应的编码,所以无论如何转换都不会乱码。

而页脚的html则是通过后端实现中的框架模式直接写入页面中输出,所以会受到浏览器强制错误编码的影响导致乱码。

至于safari的韩文,这个不敢妄言,毕竟对韩文编码不熟悉。值得一提的是,微博的框架JS是经过打包程序输出,去除了所有的注释,理论上不会包含有大于0x7F的字符。由于我在chrome下没有重现韩文的问题,所以暂时没法定位问题。

PS:
后端已经在鸟哥@laruence 的带领下实现了并行输出,目前正在逐步改造和测试中,完全并行化的输出请拭目以待:D

基本上楼上两位已经分析清楚了,新浪微博使用了类似 Bigpipe (并不是真正的Bigpipe,因为没有做到后端的多线程) 的页面加载方式。为的是减少用户等待时间,提高加载速度。在步骤 5 中没有出现乱码的那部分内容是由 javascript 动态加载的 DOM 结构,这部分内容的编码在浏览器接收 javascript 代码的时候已经确定了。想弄清楚问题可以试试看找找 Bigpipe 的资料。

问题的原因 是JSON将中文字符转成了unicode编码,不管浏览器被设定为什么编码,都可以转换成你设定的编码, 除非不能转换? 比如字符集不支持该字符。或者浏览器不支持的字符集。

你可以研究研究JSON的协议: http://json.org/

很简单,有两点:

  1. JS文件根据你的文本编码来决定,比如你是UTF-8的文本就是UTF-8,如果你是GB2312就是GB2312
  2. 外部引用字符需要设置charset,如下:
<script type="text/javascript" src="test.js" charset="gb2312"></script>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏