servlet请求编码和响应编码的乱码问题

抽举几个问题
1.为何为乱码?为何乱码表现(个数、形式)还不尽一致?
2.为何解决乱码时对于响应需设置响应头ContentType,而请求不需要?
3.对于get请求,new String(username.getBytes(“iso-8859-1”),“utf-8”)又是何意?

一、说明

  1. 汉字字节数
    1)utf-8:3字节
    2)gb2312:2字节
    3)iso-8859-1:无中文
  2. 乱码原因:编码与解码所有的字符集不一致
  3. 编码:字符转字节
    解码:字节转字符
  4. 工具:tomcat-8.5.38;eclipse-Photon Release (4.8.0)
  5. 文中resp同response;iso同iso-8859-1
  6. 文中浏览器端为以下表单:

    其中key分别是 username(用户名) password(密码)

二、测试与结论

  1. 响应编码
    1)response.getWriter().println(“张三”);
          结果:??
          查询知:浏览器端解码gb2312

    2)response.setCharacterEncoding(“utf-8”);
          response.getWriter().println(“张三”);
          结果:三个未知字样
          查询知:浏览器端解码gb2312

    3)response.setContentType(“text/html;utf-8”);
          response.getWriter().println(“张三”);
          结果:??
          查询知:浏览器端解码iso

    4)response.setCharacterEncoding(“utf-8”);
          response.setContentType(“text/html;utf-8”);
          response.getWriter().println(“张三”);
          结果:张三
          查询知:浏览器端解码utf-8

    5)response.setContentType(“text/html;utf-8”);
          response.setCharacterEncoding(“utf-8”);
          response.getWriter().println(“张三”);
          结果:张三
          查询知:浏览器端解码utf-8

    *由上测试以及进一步测试验证得到如下结论
          (1)服务器端默认使用iso编码
          (2)setCharacterEncoding(“utf-8”):表示通知服务器使用utf-8进行编码
          (3)setContentType(“text/html;utf-8”):表示响应格式为html文本,其编码格式为utf-8
          (4)只进行setContentType(“text/html;utf-8”),浏览器默认使用iso解码;
              只进行setCharacterEncoding(“utf-8”),浏览器默认使用gb2312解码;
          (5)进一步测试:
              resp.setCharacterEncoding(“utf-8”);
              resp.setContentType(“text/html;iso-8859-1”);
              resp.getWriter().println(“张三”);
              结果:正常显示

              resp.setContentType(“text/html;iso-8859-1”);
              resp.setCharacterEncoding(“utf-8”);
              resp.getWriter().println(“张三”);
              结果:正常显示

              resp.setCharacterEncoding(“iso-8859-1”);
              resp.setContentType(“text/html;utf-8”);
              resp.getWriter().println(“张三”);
              结果:??

              说明:无关先后顺序,
                         setContentType只是有形无实的声明,
                         真正指定编码格式的是setCharacterEncoding,
                         但只有同时进行setContentType,
                         浏览器端才会使用setCharacterEncoding中指定的编码格式。

    *由结论分析测试的结果
          (1)情况1:服务器使用iso对“张三”进行编码,
                           由于iso中无中文,故编码时存储两个未知字节,
                           浏览器端使用gb2312解码时不知道是中文,所以显示两个问号。
                           (进一步测试,将"张三"换称任意个数的任意汉字,结果为对应个数的问号)
          (2)情况2:服务器使用utf-8对“张三”进行编码,存储6个字节,
                           浏览器端使用gb2312解码,2字节1中文,故显示三个未知字样,
                           进一步测试:response.setCharacterEncoding(“gb2312”);
                           即通知服务器使用gb2312进行编码,结果正常显示。
          (3)情况3:由结论(4)知服务器端是按照iso进行编码的,所以同情况1。
          (4)情况4:setCharacterEncoding(“utf-8”)表示服务器使用utf-8进行编码,
                           由结论(5)知浏览器使用setCharacterEncoding(“utf-8”)中声明的即utf-8进行解码,
                           编码和解码一致所以正常显示。
          (5)情况5:由结论(5)知二者无关先后顺序,所以同情况4。
  2. 请求编码
    1)结论声明
         (1) 浏览器默认使用utf-8编码;
         (2) get请求,参数于请求行;
         (3) post请求,参数于请求体;
         (4) tomcat8.0起默认utf-8解码,但当参数位于请求体,即post请求时服务器使用的是iso解码;
         (5) 对8.0起的tomcat服务器,如果是get请求,由于默认使用utf-8解码,故不会出现乱码;
         (6) req.setCharacterEncoding(“utf-8”):表示指定服务器的解码类型,此处表示用utf-8解码;
         (7) 字符.getBytes(“utf-8”):表示指定编码类型,此处表示用utf-8将字符转为字节存储;
         (8) new String(字节数组,“utf-8”):表示指定解码类型,此处表示使用utf-8对字节数组进行解码。

    2)测试验证
         (1) 测试post请求
              System.out.println(req.getParameter(“username”));
              System.out.println(req.getParameter(“password”));
              结果:乱码

              req.setCharacterEncoding(“iso-8859-1”);
              System.out.println(req.getParameter(“username”));
              System.out.println(req.getParameter(“password”));
              结果:乱码,且乱码表现同上

              req.setCharacterEncoding(“utf-8”);
              System.out.println(req.getParameter(“username”));
              System.out.println(req.getParameter(“password”));
              结果:正常显示

              结论:浏览器默认编码格式为utf-8,服务器默认解码为iso-8859-1。

         (2) 测试new String(“中文”.getBytes(“字符集”),“字符集”)
              System.out.println(new String(“张三”.getBytes(“utf-8”),“utf-8”));
              结果:正常显示

              System.out.println(new String(“张三”.getBytes(“iso-8859-1”),“utf-8”));
              结果:??

    3)对new String(username.getBytes(“iso-8859-1”),“utf-8”)的解释(源自网上)
         前提:在tomcat8.0以下的get请求才会涉及
         这是个反编码解码过程,具体分析如下:
         (1) 浏览器端使用utf-8对汉字进行编码
         (2) 服务器端默认使用iso进行编码;
         (3) new String(username.getBytes(“iso-8859-1”),“utf-8”)表示:
              先用ios对(2) 的编码结果进行解码,然后再使用utf-8进行编码。

你可能感兴趣的:(java,ee)