Jsp中文编码问题(上)

摘要:

  本文首先介绍了一个JSP的源文件执行过程,即需要经过三个阶段,两次编码,才能完成一次完整的输出。特别需要注意的是,在这个过程中,编码问题贯穿始终。我们知道在JSP/Servlet中,主要有以下四种方式可以设置编码,即 pageEncoding、contentType、request.setCharacterEncoding 和 response.setCharacterEncoding,在本文中,我们就这四种方式进行深入的介绍和总结。


一. JSP的执行过程与编码设定概述

  在JSP/Servlet中,主要有以下四种方式可以设置编码,其中前两个只能应用于JSP中,而后两个可以用于 JSP 和 Servlet 中。

  • pageEncoding=”UTF-8”;
  • contentType=”text/html;charset=UTF-8;
  • request.setCharacterEncoding(“UTF-8”) ;
  • response.setCharacterEncoding(“UTF-8”)。

  pageEncoding是jsp文件本身的编码;contentType的charset是指服务器发送给客户端时的内容编码;

  JSP要经过两次的“编码”,第一阶段会用pageEncoding,第二阶段会用utf-8至utf-8,第三阶段就是由Tomcat出来的网页, 用的是contentType。

  事实上,一个JSP的源文件需要经过三个阶段,两次编码,才能完成一次完整的输出,这三个阶段是:

  第一阶段:转译(.jsp -> .Java;pageEncoding -> UTF-8)。将jsp编译成Servlet(.java)文件,用到的指令是pageEncoding。在编译过程中,根据pageEncoding=“XXX”的指示,找到编码的规则为“XXX”,然后服务器将JSP文件编译成.java文件时会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8编码的JAVA源码(即.java)。

  第二阶段:编译(.java -> .class;UTF-8 -> UTF-8)。从Servlet文件(.java)到Java字节码文件(.class),从UTF-8到UTF-8。在这一阶段中,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。JAVAC用UTF-8的encoding读取java源码,编译成UTF-8编码的二进制码(即.class),这是JVM对常数字串在二进制码(Java encoding)内表达的规范。这一过程是由JVM的内在规范决定的,不受外界控制。

  第三阶段:是Tomcat(或其他container)载入和执行阶段二的Java二进制码,输出的结果到客户端的(UTF-8 -> contentType)过程。从服务器到浏览器,在这一过程中用到的指令是contentType。服务器载入和执行由第二阶段生成出来JAVA二进制码,输出的结果,也就是在客户端可见到的结果,在这次输出过程中,由contentType属性中的charset来指定,将UTF8形式的二进制码以charset的编码形式来输出。如果没有人为设定,则默认的是ISO-8859-1的形式。

  特别需要注意的是,pageEncoding 的默认值是 “ISO-8859-1”, contentType 的默认值是 “text/html;ISO-8859-1”。

  注意: 第一、三两个阶段的转码个人感觉联想到Sting转码更容易理解些,例如 :new String(name.getBytes(“ISO-8859-1”), “utf-8”)。


二. pageEncoding=”UTF-8”

  pageEncoding=”UTF-8” 的作用是设置JSP编译成Servlet时使用的编码。通常,在JSP内部定义的字符串(直接在JSP中定义,而不是从浏览器提交的数据)出现乱码时,很多都是由于该参数设置错误引起的。例如,你的 JSP文件中含有中文字符,而在JSP中却指定pageEncoding=”iso-8859-1”,就会导致中文字符显示异常。看下面的例子:

<%@ page language="java" pageEncoding="iso-8859-1" import="java.util.*" %>

<html>
  <head>
    <title>哈哈</title>
  </head>
  <body>
     中文 <br>
  </body>
</html>
   
   

在其编译为Servlet后,其源码(片段)如下所示:

public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {

      // ...

      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      out.write("    <title>哈哈</title>\r\n");
      out.write("  </head>\r\n");
      out.write("  <body>\r\n");
      out.write("   \t 中文 <br>\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");

      // ...
   
   

访问该页面,页面显示如下:

               pageEncoding.png-13.9kB

  我们可以看到,由于pageEncoding被指定为”iso-8859-1”,导致其在由服务器将JSP文件编译成.java文件过程中,在使用“iso-8859-1”读取jsp并翻译成统一的UTF-8编码的JAVA源码时,所有的中文字符被转成乱码,并使得其呈现给用户的响应也包含乱码。特别地,该属性还有一个功能,就是在JSP中不指定contentType参数,也不使用response.setCharacterEncoding方法时,指定对服务器响应的内容进行编码。


二. contentType=”text/html;charset=UTF-8”

  contentType=”text/html;charset=UTF-8” 的作用是将上述第二阶段所生成的UTF8形式的二进制码以charset的编码形式来输出到客户端,如果设置不当的话,会出现乱码。看下面的例子:

<%@ page language="java" contentType="text/html;iso-8859-1" import="java.util.*" 
    pageEncoding="utf-8"%>

<html>
  <head>
    <title>哇哈哈</title>
  </head>
  <body>
     哇哈哈 <br>
  </body>
</html>
   
   

在其编译为Servlet后,其源码(片段)如下所示:

public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {

      // ...

      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      out.write("    <title>哇哈哈</title>\r\n");
      out.write("  </head>\r\n");
      out.write("  <body>\r\n");
      out.write("   \t 哇哈哈 <br>\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");

      // ...
   
   

访问该页面,页面显示如下:

               contentType.png-13.1kB


三. request.setCharacterEncoding(“UTF-8”)

  request.setCharacterEncoding(“UTF-8”)用来指定对浏览器发送来的数据以特定的字符集进行重新编码,常用于对 POST 请求参数进行解码。具体见下一个博客 JSP中文编码问题(下)中 “POST 请求的请求参数为中文情形” 一节。


四. response.setCharacterEncoding(“UTF-8”)

  response.setCharacterEncoding(“UTF-8”)的作用是:在服务器将响应返回到浏览器前,对响应使用指定字符集进行重新编码。一旦使用了该种方式,即使该响应页面指定了具体的 contentType,也将失效,即response.setCharacterEncoding()方法会覆盖contentType的值。看下面的例子:

<%@ page language="java" contentType="text/html;iso-8859-1" import="java.util.*" 
    pageEncoding="utf-8"%>

<html>
  <head>
    <title>哇哈哈</title>
  </head>
  <body>
     哇哈哈 <br>
  </body>
</html>
   
   

在其编译为Servlet后,其源码(片段)如下所示:

public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException {
      response.setCharacterEncoding("UTF-8")
      // ...

      out.write("<html>\r\n");
      out.write("  <head>\r\n");
      out.write("    <title>哇哈哈</title>\r\n");
      out.write("  </head>\r\n");
      out.write("  <body>\r\n");
      out.write("   \t 哇哈哈 <br>\r\n");
      out.write("  </body>\r\n");
      out.write("</html>\r\n");

      // ...
   
   

访问该页面,页面显示如下:

               setContentType.png-13.6kB


五. 四种编码设定方式之间的相互影响以及作用的优先级

  根据上文内容,我们得出以下三点:

  • 在指定JSP编译成Servlet时使用的编码时,优先级为: pageEncoding=”UTF-8” > contentType=”text/html;charset=UTF-8”

  • 在指定服务器对响应内容的编码时,优先级为:response.setCharacterEncoding(“UTF-8”) > contentType=”text/html;charset=UTF-8” > pageEncoding=”UTF-8”

  • request.setCharacterEncoding(“UTF-8”) 只用来指定对浏览器发送来的请求数据的解码方式。


  本文内容转自: JSP中文乱码问题终极解决方案(上)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值