浅谈字符编码

编程中常会遇到一些字符处理问题,这里来介绍一下前后台关于字符编码的问题。

常见的字符编码种类如下:

常用字符编码 描述 补充说明
ASCII 1字节,字符范围0-127,包含26个基本拉丁字母、阿拉伯数目字和英式标点符号。 只能显示现代美国英语,即使其扩展 EASCII (字符范围0-255)也只解决了部分西欧语言的显示。
ISO-8859-1 1字节,字符范围0-255,兼容 ASCII 只支持欧洲语言,在其他编码的配合下可以显示中文等。
GB2312 / GBK 1-2字节,兼容 ISO-8859-1 ,一般ascii码占1字节,其他占2字节。 GB2312 支持简体字; GBK 支持简/繁体字,兼容 GB2312 。(注意:区分全角和半角)
Unicode 定长2字节(也有4字节的)。 不兼容任何编码 ,但是定长编码便于计算机处理。包含所有语言的字符,但占用空间大。
UTF-8 1-6字节,一般英文占1字节,中文占3字节,包含所有语言。兼容 ISO-8859-1 针对 UnicodeISO-8859-1 不兼容,且占用空间大的问题,产生了 UTF-8 。utf8为UTF-8的简写,只有数据库(mysql)中使用utf8,其他推荐使用UTF-8(IE可能不识别utf8)。

HTML 编码问题

因为HTML语言的本身特性导致一些字符需要转换为 字符实体 才可使用。这实际上是常见的 转义 操作, 和本文所要说的的 编码 并不是一件事。

在线工具:HTML编码/解码

常见转义符号如下:

符号(描述) HTML转义 XHTML转义
(空格)    
<(大于号) &lt; &#60;
> (小于号) &gt; &#62;
" (冒号) &quot; &#34;

URL 编码问题

URL 只能使用 ASCII 字符集 来通过因特网进行发送,所以 非ASCII 需要编码才可以在URL中使用。

URL 编码使用 “%” 其后跟随两位的十六进制数来替换非 ASCII 字符。

URL 不能包含空格。URL 编码通常使用 + 来替换空格。

前端编码

encodeURI()encodeURIComponent()

常用方法 说明
encodeURI() 常用于URL整体编码,不会对URL保留字符进行URL转义,如 ? / ! / : 等共10个。
encodeURIComponent() 常用于参数值编码,会对URL保留字符进行URL转义。

URL 保留字符

URL 具有一些保留字符,他们具有特殊含义,当传参中有保留字符,应该转义,否则可能导致异常。

URL 保留字符 说明
+ 表示空格。
/ 用于分隔目录或子目录。
? 用于分隔 URL 和参数。
% 指定特殊字符。
# 表示页面中的书签。
& 参数间的分隔符。
= 指定参数的值。

二次编解码问题

一般字符乱码问题,是因为 c/sb/s 字符集不同造成的,所以先客户端编码,后服务端解码即可避免。但是我们会经常遇到,有时 不编解码 / 编解码 / 两次编解码 都不会出现字符乱码问题。

为了便于理解,需要知道以下信息:

  • URL只能存在 ASCII字符
  • Tomcat的 request.getParameter(paramName) 默认是 iso-8859-1 解码。
  • encodeURI()encodeURIComponent() 使用的是 UTF-8 编码。
  • UTF-8 / ISO-8859-1 / GBK 包含 ASCII 且都是相同的码值。

以下为字符 的二次编解码过程:

因为第一次编码后只存在 ASCII字符 ,所以第二次 UTF-8编码 等同于 iso-8859-1编码

web-character

1
2
// js : 二次编码
encodeURI(encodeURI(paramName));
1
2
3
4
// servlet : 二次解码
URLDecoder.decode(request.getParameter(paramName), "UTF-8")
// struts2 : 二次解码
URLDecoder.decode(URLDecoder.decode(paramName, "UTF-8"), "UTF-8");

HTTP 编码问题

理解了二次编码问题我们就可以分析和解决 get方法 乱码问题,但对于 SpringMVC 还有更方便的方法。

以下只针对 SpringMVC 乱码问题

GET

修改 tomcat 配置文件 conf/server.xml ,添加编码和工程编码一致,推荐使用 UTF-8

因为 URL 只能存在 ASCII 字符集 ,所以浏览器默认会对汉字进行编码。

1
2
3
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>

POST

web.xml 中配置 CharacterEncodingFilter 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--字符过滤器(只针对post)-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

IDE 相关

IDEA 中的 ReloadConvert

一般IDE会使用其默认设置解读文件,如果IDE的字符集和文件本身的字符集不同就会出现乱码。

此时可以改变编码方式,如IDEA中会出现两种方式。

  • Reload : 重载,使用指定的编码方式解读文件,文件本身编码不改变。
  • Convert : 转变,将当前看到的内容以指定的编码方式写入到文件中,文件本身编码可能改变。