1.不可避免的编码转换.
计算机只能保存和理解二进制字节,而文字实际上是一种图形,所以要使用一种编码方法将图形转换为对应的二进制字节.在Java中这种编码为Unicode,使用16个二进制位表示一个字符,包含基本所有语言的任何字符.
在中文Windows系统中默认使用GBK,而OSX中默认使用UTF-8.
各种环境中的文字编码可能是不同的,但是每种编码最终映射到的字符却是相同的.所以在各种环境之间交换文本时就需要转换编码.这种转换正确进行的前提是知道源文本的编码.这就好像读一段用英文写的文字,如果你不知道是用英文写的,而当做阿拉伯语去读,那结果肯定是一团糟.
2.Java中的编码转换.
使用Java从硬盘中读取一个文件,由于文件是自己的,那当然知道它是用什么编码写的.假设为GBK.
Java中有这样的API
Reader reader = new InputStreamReader(new FileInputStream("filename"),"GBK")
从上面一句代码可以看到,该API使用构造方法的第二个参数传入源文本使用的编码.之后在reader上调用的所有读方法,都会将读到的GBK字符转换为Unicode保存在内存中.
在写入文件时使用如下语句.
Writer writer = new OutputStremWriter(new FileOutputStream("filename"),"GBK")
此时,在writer上调用写方法,会将内存中保存的Unicode转换为GBK写入文件.
若在上述两个语句中没有传入编码,则会默认使用当前操作系统的默认编码.
在Java中若要保证不出现乱码,只需要遵守读写文件编码一致的原则即可.
3.Tomcat中的文件编码
WEB服务器都要处理HTTP请求,但是如何知道一个HTTP请求所使用的编码呢?
首先构造HTTP请求时path部分只使用英文,不会有乱码问题.但是QueryString部分难免要使用非英文字符,在程序中我们可以使用UrlEncoder来进行编码.所以这部分的编码自己知道.
其次,在HTTP请求的HEAD中有个ContentType提供请求体所使用的编码信息.
在Tomcat中有两个参数用来配置解析请求时所使用的编码,如果均无设置,则默认使用iso-8859-1.
其中URIEncoding顾名思义,是Tomcat用来解析请求的Uri的编码,包括QueryString.
Tomcat会读取请求HEAD中的ContentType提供的编码信息解析请求体(在处理POST请求时很有用)
useBodyEncodingForURI这个参数表明是否需要使用请求头中的编码信息解析Url本身.
所以HTTP请求的url和请求体使用相同的编码,且HEAD中通过ContentType提供了正确的编码信息,那么只需要配置useBodyEncodingForURI="true"即可正确处理编码问题.
如果url和请求体所使用的编码不同(极不推荐的做法),那么需要正确配置URIEncoding参数.建议,如果服务器要处理HTTP GET请求一定要配置该参数.
由于使用的工具和方法不同,可能会生成一些不规范的HTTP请求,在HEAD中没有提供编码信息,所以需要设置一个默认编码,此时需要在HttpServletRequest对象上调用setCharacterEncoding("charset")告知服务器要使用的默认编码.
正确处理一个HTTP请求后,还要将响应以客户端能够接受的编码写回,可以调用HttpServletResponse对象的setCharacterEncoding("charset")来设置该编码.