jsp/servlet中的编码问题

首先声明以下只是我个人的看法,有部分观点与网上人云亦云的观点不一样,不过凡事必恭亲,我还是相信自己测试的结果

推荐一个很好地URL编码详解http://www.ruanyifeng.com/blog/2010/02/url_encoding.html

与网上的共识是

JSP中

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">

二者里面的contentType="text/html; charset=UTF-8"作用是一样的,只不过后者优先级高于前者
相当于resposne.setContentType("text/html;charset=utf-8")作用是指定HTTP响应的编码,同时指定了浏览器显示的编码
即服务器将页面以utf-8传输到浏览器,浏览器再以utf-8显示

pageEncoding="UTF-8" 指定的jsp页面本身的编码为utf-8,同时在被服务器转换为.java文件时采用utf-8编码(默认使用iso-8859-1),
但是.java文件编译为.class文件统一使用utf-8编码(JVM规定如此)
pageEncoding指定的编码一定要与JSP保存的编码一致
可以在window-preference-web-jsp Files修改jsp默认保存编码(已保存的JSP编码无法修改,只能右击修改)

最好将contentTypepageEncoding指定的编码一致

以下关于JSP页面的不同提交方式使用的编码是我与网上一些观点的不同
向服务器提交数据的方式有get和post

以下是测试
<body>
    <form action="/webExer/LoginServlet" method="post">
        登录:<input type="text"><br> 验证码:<input type="text"
            name="imageCode">
        <!--             <img src="/webExer/ImageCodeServlet"><br> -->
        <input type="submit" value="提交">
    </form>
    <input type="button" value="get跳转" onclick="jump()">
    <script type="text/javascript">
        function jump() {
            window.location.href = "/webExer/LoginServlet?imageCode=get提交";
        }
    </script>
</body>

public class LoginServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //request.setCharacterEncoding("UTF-8");
        //response.setContentType("text/html;charset=utf-8");
        String imageCode=request.getParameter("imageCode");
        String x = new String(imageCode.getBytes("ISO-8859-1"),"UTF-8");
     String xx=new String(imageCode.getBytes("ISO-8859-1"),"GBK");
     //原生数据 System.out.println(imageCode);
     //转码后数据 System.out.println(x);
System.out.println(xx); PrintWriter out
=response.getWriter(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }

当访问JSP时

POST方式

点击post提交按钮时form表单以post向后台传数据,并在控制台打印获得的数据

指定为UTF-8编码

<%@ page language="java" contentType="text/html; charset=UTF-8"

后台中可以发现原生数据是乱码,但是IS0-8859-1转UTF-8后数据正常显示发现post提交过来的是ISO-8859-1编码

那为什么IS0-8859-1转GBK是乱码呢?因为JSP页面是UTF-8,浏览器用的UTF-8编码显示JSP页面,

post提交时默认采用当前浏览器使用的编码即UTF-8提交,但是服务器有自己的编码,在POST提交方式下,注意我说的是在POST提交方式下,跟GET无关,tomcat默认的编码是ISO-8859-1(在server.xml里修改对该默认编码无效,下面会进行测试),于是tomcat又用IS0-8859-1重新编码了一次,也就是传到servlet里的数据经过了两次编码,先UTF-8,在ISO-8859-1,所以拿到IS0-8859-1解码的字节后转GBK当然会乱码了。(网上大都说get方式是先采用浏览器面默认编码,在由服务器用IS08859-1进行二次编码,但我测试的是post方式这样做的,get方式不是,get方式会在下面介绍,强烈建议自己动手试试

解决办法一般用request.setCharacterEncoding("UTF-8");但是该方式只能用于post方式

 

request.setCharacterEncoding("UTF-8");

 

 

这是在控制台显示,如果要在浏览器中正常显示别忘了加上response.setContentType("text/html;charset=utf-8");

为了证明自己的测试结果,我把contentType设置为"text/html; charset=GBK"试试

 

contentType="text/html; charset=GBK"

 

String imageCode=request.getParameter("imageCode");
        String y=new String(imageCode.getBytes("UTF-8"));
        String yy=new String(imageCode.getBytes("GBK"));
        String x = new String(imageCode.getBytes("ISO-8859-1"),"UTF-8");
        String xx=new String(imageCode.getBytes("ISO-8859-1"),"GBK");
        System.out.println(imageCode);
        System.out.println(y);
        System.out.println(yy);
        System.out.println(x);
        System.out.println(xx);

可以看到只有 String xx=new String(imageCode.getBytes("ISO-8859-1"),"GBK");没有乱码,证明我的想法是对的

再证明修改server.xml对POST方式默认编码无效

在servler.xml中指定任意编码

结果

 

与前面GBK编码测试结果一样,说明server.xml指定的编码对POST方式无效,再次证明了我的想法

 

GET方式

先测试UTF-8(此时server.xml里未指定编码)

GET方式就是在URL后面拼接参数,我在JS里传了一个死参数

 

<input type="button" value="get跳转" onclick="jump()">
    <script type="text/javascript">
        function jump() {
            window.location.href = "/webExer/LoginServlet?imageCode=get提交";
        }
    </script>

 

servlet中

     String imageCode=request.getParameter("imageCode");
        String y=new String(imageCode.getBytes("UTF-8"));
        String yy=new String(imageCode.getBytes("GBK"));
        String x = new String(imageCode.getBytes("ISO-8859-1"),"UTF-8");
        String xx=new String(imageCode.getBytes("ISO-8859-1"),"GBK");
        System.out.println(imageCode);
        System.out.println(y);
        System.out.println(yy);
        System.out.println(x);
        System.out.println(xx);

控制台打印

 

 

可以看到jsp传过来的参数直接获取就能正常显示

 

String y=new String(imageCode.getBytes("UTF-8"))能正常显示,即传过来的数据是UTF-8编码

也就是说get方式传到后台的数据是UTF-8,那么这个UTF-8编码是不是浏览器当前默认编码呢?

我用GBK试了一下

 

contentType="text/html; charset=GBK

 

很奇怪结果全是乱码,但是浏览器默认编码确实变了

 

注意到一个细节

使用contentType="text/html; charset=UTF-8”时浏览器URL参数显示为中文

 

 

使用contentType="text/html; charset=GBK”时浏览器URL参数显示其他的编码

不知道用的什么编码,但是知道春"和"节"的GBK编码分别是"B4 BA"和"BD DA"。于是试了试把“get提交”改成“get春节”

说明浏览器确实用的GBK将GET参数编码了,也就是说确实使用浏览器当前默认编码对GET参数编码

既然客户端是GBK编码,如果与POST方式一样tomcat用ISO-8859-1二次编码,那为什么在后台 

String xx=new String(imageCode.getBytes("ISO-8859-1"),"GBK");ISO-8859-1转GBK获取还是乱码呢?

说明我的tomcat获取GET参数不是用的ISO-8859-1二次编码,又因为GBK用UTF-8转码是转不过去的

原因GBK用UTF-8不能转码参照http://my.oschina.net/chape/blog/201725

而前面的用UTF-8测试的例子只有

String imageCode=request.getParameter("imageCode")和String y=new String(imageCode.getBytes("UTF-8"))

能取到正常值,所以我猜测tomcat直接用了UTF-8解码,也就导致了用过客户端用GBK后台用UTF-8转不了码,只能乱码了

于是我又做了个测试

在tomcat的server.xml里设置服务器编码URIEncoding="ISO-8859-1"

如果server.xml设置编码对GET方式有效的话,tomcat肯定是用ISO-8859-1二次编码了

在原来的GBK中再次测试

发现只有String xx=new String(imageCode.getBytes("ISO-8859-1"),"GBK");取到正常值

即修改server.xml编码对GET方式是有效的

其过程应该是客户端用GBK编码,服务器端用ISO-8859-1编码,我在servlet里手动用ISO-8859-1转码

这样看来我的tomcat在GET方式下默认编码应该是UTF-8,而不是网上很多人说的ISO-8859-1,

至于为什么UTF-8我也不清楚,我用的tomcat8.0,JDK8,项目保存为GBK(UTF-8也试过)

!后来重新试验过,客户端使用的UTF-8,server.xml里指定ISO-8859-1二次编码,

在servlet里直接new String(imageCode.getBytes("ISO-8859-1")也能获取到正常值,String

里获取的ISO-8859-1编码后用的本地默认编码进行解码,本地默认编码就是你的.java文件保存的编码(在eclipse指的是workspace指定的编码),我保存为UTF-8,所以能获取到正常值,如果改为GBK则会乱码。

所以猜测servlet里解码采用的编码是你的平台默认编码!

隔了一段时间后我换了tomcat7,发现在server.xml默认没有编码的情况下,get和post提交在servlet里都是经过ISO-8859-1编码,与前面的结果不太一样,看来是tomcat版本不太,服务器采用的编码方式有所差异,

这样的话最好在tomcat的server.xml里指定get方式的二次编码为ISO-8859-1,在用过滤器统一编码的时候也方便处理

 

这样要想GET方式提交的参数不乱码最好的方式是在客户端使用UTF-8编码,如果一定要用其他编码,

最好用JS将参数编码为UTF-8再提交到后台

有一点需要知道:POST下的request.setCharacterEncoding("UTF-8")对GET方式无效

至于servlet中的响应编码使用response.setContentType("text/html;charset=utf-8")就可以了,该方法

指定HTTP的响应编码为UTF-8并通知浏览器以UTF-8编码显示。

 

总结:

1丶 不管get还是post方式提交的参数都是采用浏览器当前编码

2丶 针对tomcat7及以下版本,参数传入servlet后,两种方式默认情况下在servlet里采用ISO-8859-1解码,

针对中文,比如浏览器采用GBK,servlet可以使用new String(value.getBytes("ISO-8859-1"),"GBK")获取正确参数

  针对tomcat8版本,get方式提交的参数传入servlet后采用的平台默认编码解码

3丶 request.setCharacterEncoding()只对post方式有效,针对get方式,可以二次转码获取中文,或者在tomcat下的server.xml里指定编码

4丶 response.setCharacterEncoding()设置HTTP相应编码

     response.setContentType()设置HTTP相应编码并通知浏览器解码方式

 

 

 

 

 

 


posted on 2016-08-17 22:35  pokid  阅读(1134)  评论(0编辑  收藏  举报

导航