WEB 开发和应用中的文本编码问题总结

  Windows 平台上大部分用于 WEB 代码编辑器,打开一个文本文件时都是先根据 BOM 头选择字符集/编码,缺少则根据 <meta http-equiv="Content-Type" content="text/html; charset="> 选择,再缺少则根据“在‘编码->字符’映射过程中是否有‘无法显示的字符’”自动选择(可能选错);而保存时根据 <meta http-equiv="Content-Type" content="text/html; charset="> 更新文件编码(若显示时正常则会正确转码,但可能因为没写 BOM 头而影响下次打开时的显示)。
  Windows 平台上一般的文本编辑器,打开一个文本文件时先根据 BOM 头选择字符集/编码,缺少则根据“在‘编码->字符’映射过程中是否有‘无法显示的字符’”自动选择(可能选错);而保存时由用户自行选择编码。用这类文本编辑器将 HTML 文件存为新的编码时,会违背 <meta http-equiv="Content-Type" content="text/html; charset=">,或者只修改 <meta http-equiv="Content-Type" content="text/html; charset="> 使其违背原有编码和 BOM 头——那么,下次打开文件编辑时就只能靠 BOM 头才能维持完全正常显示——更麻烦的是,大多浏览器恰恰是根据从 <meta http-equiv="Content-Type" content="text/html; charset="> 判断编码的,这就直接影响了应用。即使浏览器优先检查 BOM 头(比如 IE),也只作用于静态网页,在服务器上由脚本(假设脚本有 BOM 头)动态形成的网页,是没有 BOM 头的。
   其他 OS 上的文本编辑器,基本上都无视 BOM 头的。


  浏览器在递交表单时不管 method 与 enctype 怎么定义,默认都是根据 <meta http-equiv="Content-Type" content="text/html; charset="> 选择字符集/编码的,即使文件有 BOM 头都不看。但是根据 enctype 的不同会选择不同的传输方式。
  若表单 enctype 选了默认的 application/x-www-form-urlencoded(即 URL 形式),由于 IE 选项里有一条默认为“用 UTF-8 发送所有 URL”(绝大多数浏览器都是如此),所以导致不论是 GB2312 编码、Unicode(UCS-2)编码还是标准 UTF-8 编码都会被写成 UTF-8 的传输形式:%XX%XX…(省略 %00)——注意,仅仅是按照 UTF-8 传输方式传输,并没有真正改变编码方式。
  表单使用 enctype="multipart/form-da ta" 的话就不会用任何 UTF 传输方式了,数据和单机文件一样。UTF-8 这个名词有两个概念,即是传输方式又是编码方式。在编码方式下,你要说它等于 UCS-4,可偏偏又是动态长度,介于(UCS-1——UCS-4 之间),不像 UCS-2(即 unicode.org 版 Unicode)一样存储单个字符时只能用 2 字节,所以是独立的编码方式。
  浏览器在递交表单时若增加了 accept-charset 属性(非 IE 浏览器)或 on submit="document.charset=' ';"(IE 浏览器),则以这里指定的编码发送表单,而不再参照 <meta http-equiv="Content-Type" content="text/html; charset=">。这通常用于将表单递交给另一编码的服务器脚本,此时表单指定的是那个服务器脚本的编码。
  在没有表单引导的情况下,在浏览器地址栏直接输入查询语法也可以用 GET 这种 method 递交信息,此时无法使用 <meta http-equiv="Content-Type" content="text/html; charset=">,所以是用了浏览器甚至是操作系统的默认编码,当然,也用了 URL 形式。
  WEB 服务器要无损地使用你递交的信息(二进制意义上的无损),就必须设置 Session 的编码方式和你信息的编码方式一样,即使服务器端脚本本身是用其他编码写的(或者脚本代码声明为其他编码)。至于如何回应你,那倒是受着服务器端脚本代码声明的影响(表面上是这样,实际上脚本本语法部分本来就是英文,只要不作字符串变量的更改,编码不符合代码声明一般无所谓的,只要脚本本身编码和回应的 <meta http-equiv="Content-Type" content="text/html; charset="> 一致就行了),不过那又是另一个过程了。

  在 WEB 服务器没有安装特定的 ISAPI 过滤器、ISAPI 扩展、模块、插件,或者用户自行上传服务器端转码脚本、程序的情况下,WEB 服务器是不会自动转码的。WEB 服务器又是数据库服务器的客户端,数据库服务器倒可能有转码功能。

服务器端脚本代码声明:
ASP:@ CODEPAGE=num_str
PHP:mb_internal_encoding(str)

服务器端转码脚本:
ASP.NET(全局):@ Page ResponseEncoding=str
PHP(全局):mb_http_output(str); ob_start('mb_output_handler')
PHP(字符串):mb_convert_encoding((str, to_encoding[, encoding]))