zoukankan      html  css  js  c++  java
  • 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相应编码并通知浏览器解码方式

    
    
  • 相关阅读:
    VS中,如何将存在于解决方案里,但是没有显示出来的文件(或文件夹)显示到项目中。
    (转)分布式系统编程,你到哪一级了?
    领域驱动架构学习总结
    Java多线程总结
    MySQL更新优化
    MySQL查询优化
    MySQL索引
    MySQL优化
    MySQL联接操作
    MySQL架构
  • 原文地址:https://www.cnblogs.com/pokid/p/5782196.html
Copyright © 2011-2022 走看看