JSP 乱码问题

来源:互联网 发布:mac防火墙设置 编辑:程序博客网 时间:2024/06/06 07:26

JSP开发通常会遇到乱码问题,这几天参考网上的文章和自己的实验(浏览器版本ie11,chrome32.0.1700.107 ),总结一下乱码出现的原因,以及如何解决乱码问题。

首先,为了明白乱码出现的原因,我们需要了解一下知识:

1、浏览器对页面如何编码、如何解码?

2、服务器对页面如何编码、如何解码?


一次简单的http请求过程为:

1、浏览器对请求的URL和参数,进行编码,发送给服务器。

2、服务器对URL和参数进行解码,然后将要返回给浏览器的信息,进行编码发送给浏览器。

3、浏览器对从服务器返回的信息进行解码,然后展现出来。


  • 先讲第2步

A:服务器对URL和参数进行解码。

借用一张图:


浏览器提交http请求有两种方式:get方式和post方式。

先讲get的方式:

get的方式,参数位于queryString里,保存在http的head里。

tomcat的server.xml里可以对<Connector port="8080" protocol="HTTP/1.1"  connectionTimeout="20000"  redirectPort="8443" />

这里可以增加两个参数,一个是URIEncoding="UTF-8",useBodyEncodingForURI=true

如果未设置这两个参数,tomcat默认采用“iso-8859-1”的方式进行解码。

URIEncoding表示服务器对get方式提交的数据进行解码的方式(URI包括的内容如上图所示,包括pathInfo和queryString)。

useBodyEncodingForURI,表示对queryString的解码按照对body的编码方式解码,(感觉这里准确的名称应该是useBodyEncodingForQueryString)

再讲post的方式:

post的方式,参数在http的body里。

对于post方式提交的参数,tomcat默认也是采用“iso-8859-1”的方式进行解码,我们可以通过指定request.setCharacterEncoding("UTF-8"),来指定服务器采用什么方式解码。这里需要注意的是,request.setCharacterEncoding("UTF-8")必须在getParameter方法之前调用。

B:服务器对要返回的信息进行编码

对于jsp页面的编码,涉及到几个参数,分别为:pageEncoding、contentType和response.setCharacterEncoding("UTF-8")

<%@ page pageEncoding ="ISO-8859-1" contentType ="text/html;charset=UTF-8"%>

简单的理解为:

pageEncoding表示该jsp页面的编码格式,在由jsp->servlet转化的过程中,tomcat会按照pageEncoding指定的编码格式来进行解码。

contentType表示服务器发送给客户端的信息采用的编码。

但是:

这两个参数的作用相互影响,相互覆盖。只有当两个参数都设置了的时候,pageEncoding和contentType 才能都起作用。

因为,严格来讲:

pageEncoding和contentType都可以设置JSP源文件和响应正文中的字符集编码。但也有区别:

设置JSP源文件字符集时,优先级为pageEncoding>contentType。如果都没有设置,默认ISO-8859-1。
设置响应输出的字符集时,优先级为contentType>pageEncoding。如果都没有设置,默认ISO-8859-1。
也就是说如果,只设置了pageEncoding或者只设置了contentType,那么jsp源文件和响应正文中的字符集编码就被设置成了这个唯一设定的编码。
(以上规则,在tomcat6下测试通过)

所以说:为了避免上述的默认规则,简化设置逻辑,这两个参数我们都应该设置。


而response.setCharacterEncoding("UTF-8")也是用来设置响应正文的字符集编码,这样就和contentType的作用有部分重复。

contentType的主要作用是使客户端浏览器,区分不同种类的数据,并根据不同的MIME调用浏览器内不同的程序嵌入模块来处理相应的数据。还可以通过charset设置数据编码。而setCharacterEncoding("utf-8")是设置响应内容的编码。

注意,response.setCharacterEncoding("UTF-8")会覆盖contentType中charset的设置,(从chrome浏览器里看到,如果jsp里设置contentType的charset为“UTF-8”,在response.setCharacterEncoding("GBK")之后,contentType的charset变为GBK。)而且,response.setCharacterEncoding("UTF-8"),要在在response.getWriter()被调用之前调用

  • 再讲第3步,浏览器对从服务器返回的信息进行解码
浏览器解码是根据http头中contentType中的charset来进行解码的,注意这里所说的ContentType是指http头的ContentType,而不是在网页中meta中http-equiv的ContentType(ie11、chrome下测试通过)。由于response.setCharacterEncoding("UTF-8")会覆盖contentType中charset的原本设置,所以如果调用了response.setCharacterEncoding("UTF-8"),那么浏览器就是按照response.setCharacterEncoding("UTF-8")指定的编码来解码的。
可以通过浏览器的设置里查看网页编码格式,一般选择为“自动检测”,此时浏览器就按照contentType的charset来解码了,另外,IE的某些版本会有“始终以UTF-8发送URL”的选项,那么contentType 就不起作用了。
  • 最后讲第1步,浏览器对请求的URL和参数,进行编码
浏览器如何对pathInfo、get和post的数据进行编码。
浏览器对get和post的数据是根据contentType的charset来进行编码的。(ie11、chrome下测试通过)而对pathInfo是采用“UTF-8”编码的。(ie11、chrome下测试通过)

对于浏览器的编码和解码,依赖于目前页面的contentType。但是对于新建tab页,直接访问URL的情况,发现ie11和chrome的结果不同:
直接在浏览器里输入带参数的url,chrome会将参数用UTF-8编码,而ie会将参数用gbk或者是gb2312编码。


----------------------------------------------------我是分割线---------------------------------------------------------------------------------------------------------------------


从上面的结果猜测原因,浏览器根据contentType,设置了浏览器的编码方式,此时,如果从当前页面,通过<a>标签链接跳转页面,或者在当前页面提交表单,浏览器会根据当前页面设置的浏览器编码来对get和post的数据进行编码,对于直接在浏览器栏里进行url访问的方式,ie采用默认的gbk编码而chrome采用默认的utf-8编码,对于pathInfo,ie和chrome都采用UTF-8编码。


实践总结:
为了读取参数正确:
1、tomcat设置,URIEncoding=“UTF-8”(保证pathInfo解析正确),useBodyEncodingForURI="true"(让get和post方式的解码方式相同)
2、应用里,利用过滤器,设置request.setCharacterEncoding("UTF-8")(让get和post都按照UTF-8来解码)
3、应用里,每个jsp文件设置ontentType 的charset为UTF-8,或者利用过滤器设置response.setCharacterEncoding("UTF-8")(将输出的网页编码为UTF-8格式,为了让下次从该页面,<a>标签或者post表单方式提交数据的编码为UTF-8)注意:这里虽然页面编码为UTF-8,<a>标签链接出去也按照UTF-8编码,但是为了保险,建议,用js将中文URLEncoding了。

为了页面显示正确:
1、编写jsp文件时,保存成UTF-8格式,同时设置pageEncoding=“UTF-8”

参考文章:
http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/#authorN1001C
http://hi.baidu.com/merry6046/item/e4cd16d03af9be392a35c777
等等

----------------------------------------------------再次分割---------------------------------------------------------------------------------------------------------------------
几点编码知识:
1、request.getPathInfo()、request.getParameter(),都是服务器进行解码之后的。request.getRequestURI()是没有被服务器解码过的。(这里的编码和解码指的都是URLEncode)
2、浏览器做UTF-8的URLEncoding和javaScript做的URLEncoding不完全一致。
JavaScript 的 encodeURI 或是 encodeURIComponent (兩者僅相差一些保留字是否要作編碼,如 #)目前則是都使用 RFC 3986 的方式來作編碼,所以要作 application/x-www-form-urlencoded 的編碼時(AJAX POST),就要自己把 %20 替換成 + (jQuery 目前的程式碼就是這樣做的)
Java 的 java.net.URLEncoder.encode 這個 method 也是編碼成 application/x-www-form-urlencoded 的方式,如果要遵照 RFC 3986 的定義,則可以自行再把 + 替換成 %20 即可。


0 0
原创粉丝点击