问题?
进行web开发的时候,经常会遇到字符集的问题。此类问题非常的棘手和讨厌。如果处理不当,可能永远无法搞清楚究竟发生了什么。
拾遗!
本文档旨在说明字符集对于web开发必需掌握的常规应用知识。
对于一个页面而言,最核心的三个字符集存在于1,文件编码(Page Encode)2,页面Meta信息(Meta)3,Http Headers里的Content-Type里的字符集指定(Content-Type)4,页面输出编码(Output Encode)
他们直接的关系是:
1, (Meta || Content-Type) === (Output Encode)
2, Content-Type > Meta
3, (Output Encode) !== || === (Page Encode)
以下逐一解释这些关系:
1,(Meta || Content-Type) === (Output Encode)
这里必需分服务端和客户端两块解释:
对于服务端而言,服务器会对于每一个需要输出的文件进行编码转换,转换的编码是有服务器厂商提供的可设置的特定值决定(Apache是AddDefaultCharset,ASP.Net是web.config的globalization)。这种转换不会因为输出文件字符集和服务器设定字符集相同而不发生。服务器设定的字符集最终会体现在Http Headers的Content-Type里(除非人为去掉这个值),用以告诉浏览器收到的数据信息可以用什么编码格式显示。
这里以GB2312和UTF-8举例,如果一个原始文件的编码格式是GB2312,而服务器设定的输出格式是UTF-8,那么他们需要统一转换到Unicode编码,整个过程是:GB2312->Unicode->UTF-8,反之依然。
Meta是指写在页面里的Meta元素指定的字符集信息,作用和Content-Type一样。用以告诉浏览器收到的数据信息以哪种编码格式显示。
这里必需保证的一点是,输出数据的数据格式,必需和通过Content-Type或Meta指定的编码格式一致。不然就会造成所谓的“乱码”情况发生。“乱码”并不是程序的错误,而是浏览器被指定了错误的显示方式显示数据信息的结果。
以上这段文字所描述的情况仅发生在动态内容上,对于静态内容,不会经由动态内容对应编程语言的相关的处理模块处理,所以也就不会发生“转码”这个行为。或者进一步说,对于动态而言,原始文件是什么编码根本就不重要。重要的输出编码和指定编码是不是对应。那么对于静态内容而言,静态内容本身的字符集就决定了输出的格式。至于会不会在Content-Type里指定charset,则由web server决定。
2,Content-Type > Meta
如果浏览器同时收到Content-Type和Meta信息,以谁为标准?
根据目前测试的结果(FireFox3.6.8,Chrome7,IE8)来看,首先会满足Content-Type设定,如果Content-Type里没有指明charset信息,才会以Meta为准。
那如果Content-Type和Meta都不存在呢?
根据文件的存储原则,字符集的信息被存在了文件最前面的几个字节里,而服务器在发送数据的时候,这部分信息是不会发送出去的。这样浏览器在没有收到任何字符集指令的时候就无法“确认”自己究竟该怎么办。于是浏览器会尝试进行以下行为:先缓存一部分字节(缓存多少视不同浏览器而定),然后去“猜测”这部分字节究竟是什么字符集,找一个浏览器认为最为匹配的字符集进行显示,所以任何信息发送给浏览器,浏览器都会将其显示出来,至于显示的结果是不是符合要求,浏览器就不得而知了。
下图解释了不同浏览器缓存字节的大小:
Bytes Buffered | |||
---|---|---|---|
Configuration | FireFox 3.5 | Chrome 3.0 | IE 8 |
Tranfer-Encoding: chunked
|
1134 | 1056 | 300 |
Content-Type: text/html |
204 | 1056 | 341 |
Content-Type: text/html |
166 | 204 | 218 |
Content-Type:text/html; charset=utf-8 Tranfer-Encoding: chunked |
204 | 280 | 300 |
那如果没有Content-Type设置,而且Meta的设置位置超过浏览器缓存大小呢?
这里浏览器会进行这样的处理:首先尝试“猜测”,找到他认为符合的字符集,等页面加载到一定程度并且加载到Meta信息时,浏览器发现字符集有指定,于是浏览器会清空缓存,将数据重新进行转码处理,也就是所谓的全部重新渲染。部分情况下,对于某些资源,浏览器还会重新进行请求。(某些资源是指资源中含有中文)
3,(Output Encode) !== || === (Page Encode)
这是因为对于动态资源而言,服务器必然会对资源进行转码,而无视资源本身的编码格式,所以对于任何服务器端存在的动态资源来说,格式并不一定要和服务器输出的格式相同。因为无论怎样,服务端都会进行编码输出。静态资源输出的就是它本身的编码格式。
字符集的积极意义?
对于web开发而言,了解字符集的概念应用可以有助于进行部分的性能优化。这里Google Code给出了他们的4个建议:
1, 指定Content-Type和Meta信息。
2, Meta的定义尽可能靠前部(Head之后的第二行)
3, 始终确保定义了字符集。
4, 保证设定的字符集是正确的。