`
tianhandigeng
  • 浏览: 374454 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

中文乱码问题案例分析

    博客分类:
  • java
 
阅读更多

 

案例:

1、  环境介绍:

项目采用的是 SSH 框架技术,模板视图用的是 FreeMarker ,对于编码问题做了以下的配

置:

tomcat 服务器没配置 URIEncoding 参数。

struts2 配置文件配置了如下的参数:

  <!-- 编码 -->

< constant name = "struts.i18n.encoding" value = "UTF-8" />

web.xml 进行了如下配置:

<!-- 编码处理过滤器 -->

    < filter >

       < filter-name > encodingFilter </ filter-name >

       < filter-class >

           org.springframework.web.filter.CharacterEncodingFilter

       </ filter-class >

       < init-param >

           < param-name > encoding </ param-name >

           < param-value > utf-8 </ param-value >

       </ init-param >

       < init-param >

           < param-name > forceEncoding </ param-name >

           < param-value > true </ param-value >

       </ init-param >

</ filter >

现在来看一下这三者分别的用途,

A URIEncoding 的作用是什么呢?

解析请求的 URL 是在 org.apache.coyote.HTTP11.InternalInputBuffer parseRequestLine 方法中,这个方法把传过来的 URL byte[] 设置到 org.apache.coyote.Request 的相应的属性中。这里的 URL 仍然是 byte 格式,转成 char 是在 org.apache.catalina.connector.CoyoteAdapter convertURI 方法中完成的:    

protected void convertURI(MessageBytes uri, Request request) throws Exception {

       ByteChunk bc = uri.getByteChunk();

       int length = bc.getLength();

       CharChunk cc = uri.getCharChunk();

       cc.allocate(length, -1);

       String enc = connector.getURIEncoding();

       if (enc != null ) {

           B2CConverter conv = request.getURIConverter();

           try {

                 if (conv == null ) {

                    conv = new B2CConverter(enc);

                    request.setURIConverter(conv);

                }

            } catch (IOException e){...}

           if (conv != null ) {

              try {

                   conv.convert(bc, cc, cc.getBuffer().length -  cc.getEnd());

                   uri.setChars(cc.getBuffer(), cc.getStart(), cc.getLength());

                   return ;

                   } catch (IOException e) {...}

           }

       }

        // Default encoding: fast conversion

        byte [] bbuf = bc.getBuffer();

        char [] cbuf = cc.getBuffer();

        int start = bc.getStart();

        for ( int i = 0; i < length; i++) {

            cbuf [ i ] = ( char ) ( bbuf [ i + start ] & 0xff);

        }

        uri.setChars(cbuf, 0, length);

    }

也就是说步骤是大致是这样的 ( 因为没仔细研究 tomcat 源码,所以顺序可能不会很正确 )

从上面的代码中可以知道对 URL URI 部分 ( 也就是具体的请求资源部分不包括?后面的参数 ) 进行解码的字符集是在 connector <Connector URIEncoding=”UTF-8”/> 中定义的,如果没有定义,那么将以默认编码 ISO-8859-1 解析。所以如果有中文 URL 时最好把 URIEncoding 设置成 UTF-8 编码。

 

QueryString 又如何解析? GET 方式 HTTP 请求的 QueryString POST 方式 HTTP 请求的表单参数都是作为 Parameters 保存,都是通过 request.getParameter 获取参数值。对它们的解码是在 request.getParameter 方法第一次被调用时进行的。 request.getParameter 方法被调用时将会调用 org.apache.catalina.connector.Request parseParameters 方法。这个方法将会对 GET POST 方式传递的参数进行解码,但是它们的解码字符集有可能不一样。 POST 表单的解码将在后面介绍, QueryString 的解码字符集是在哪定义的呢?它本身是通过 HTTP Header 传到服务端的,并且也在 URL 中,是否和 URI 的解码字符集一样呢?从前面浏览器对 PathInfo QueryString 的编码采取不同的编码格式不同可以猜测到解码字符集肯定也不会是一致的。的确是这样 QueryString 的解码字符集要么是 Header ContentType 中定义的 Charset 要么就是默认的 ISO-8859-1 ,要使用 ContentType 中定义的编码就要设 connector <Connector URIEncoding=”UTF-8” useBodyEncodingForURI=”true”/> 中的 useBodyEncodingForURI 设置为 true 。这个配置项的名字有点让人产生混淆,它并不是对整个 URI 都采用 BodyEncoding 进行解码而仅仅是对 QueryString 使用 BodyEncoding 解码,这一点还要特别注意。

从上面的 URL 编码和解码过程来看,比较复杂,而且编码和解码并不是我们在应用程序中能完全控制的,所以在我们的应用程序中应该尽量避免在 URL 中使用非 ASCII 字符,不然很可能会碰到乱码问题,当然在我们的服务器端最好设置 <Connector/> 中的 URIEncoding useBodyEncodingForURI 两个参数。

   也就是说对请求资源的解码和对后面所带参数的解码采用的字符集可能是不同的, URIEncoding 的设置只会告诉服务器如何对请求资源解码,而不会告诉服务器如何对请求参数解码,配置了 useBodyEncodingForURI 则告诉服务器使用 bodyEncoding 进行解码。

   根据以上分析,可以知道项目没有配置 URIEncoding useBodyEncodingForURI 两个参数。则对请求资源以及请求参数都会采用默认的 ISO8859-1 ,进行解码。

不过要说一点,虽然这里如果进行了指定,但是由于不同浏览器对 URL 进行编码的方式不同,也会出现乱码,以下是分析 :

浏览器:

1 GET 方式提交,浏览器会对 URL 进行 URL encode ,然后发送给服务器。
(1)
对于中文 IE, 如果在高级选项中选中总以 UTF-8 发送 ( 默认方式 ) ,则 PathInfo URL Encode 是按照 UTF-8 编码 ,QueryString 是按照 GBK 编码。
http://localhost:8080/example/
中国 ?name= 中国
实际上提交是:
GET /example/%E4%B8%AD%E5%9B%BD?name=%D6%D0%B9%FA

(1) 对于中文 IE, 如果在高级选项中取消总以 UTF-8 发送,则 PathInfo QueryString URL encode 按照 GBK 编码。
实际上提交是:
GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

(3) 对于中文 firefox ,则 pathInfo queryString 都是 URL encode 按照 GBK 编码。
实际上提交是:
GET /example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

很显然,不同的浏览器以及同一浏览器的不同设置,会影响最终 URL PathInfo 的编码。对于中文的 IE FIREFOX 都是采用 GBK 编码 QueryString

小结:解决方案:
1
URL 中如果含有中文等非 ASCII 字符,则浏览器会对它们进行 URLEncode 。为了避免浏览器采用了我们不希望的编码,所以最好不要在 URL 中直接使用非 ASCII 字符,而采用 URL Encode 编码过的字符串 %.
比如:
URL
http://localhost:8080/example/ 中国 ?name= 中国
建议:
URL
http://localhost:8080/example/%D6%D0%B9%FA?name=%D6%D0%B9%FA

2 、我们建议 URL PathInfo QueryString 采用相同的编码,这样对服务器端处理的时候会更加简单。

  由于我什么都没有设置,所以可以猜到,如果有中文路径或者是中文参数的 URL ,一定会出现中文乱码。假设我进行了设置,但是如果我在页面中没对中文路径和中文参数 URL 进行编码处理,那么由于不同浏览器的编码方式不同也会造成中文乱码问题,也就说终极解决方案是:所以最好不要在 URL 中直接使用非 ASCII 字符,而采用 URL Encode 编码过的字符串 %.

B < constant name = "struts.i18n.encoding" value = "UTF-8" />

这个参数有什么作用呢?

关于这个参数有什么作用,网上也进行过讨论,参考这篇文档 http://cgl198617.iteye.com/blog/1066401 ,从这篇文档可以看出这个参数的设置对于解码和页面显示有很大的作用,对于请求阶段来说相当于执行了 HttpServletRequest setCharacterEncoding 这个方法,但是对于这个方法,之前一直都没认真去理解,是不是设置了这个参数 url 中文乱码问题就解决了呢,答案是否定的, HttpServletRequest.setCharacterEncoding() 方法仅仅只适用于设置 post 提交的 request body 的编码而不是设置 get 方法提交的 queryString 的编码。该方法告诉应用服务器应该采用什么编码解析 post 传过来的内容。很多文章并没有说明这一点。看看 servlet api 也可以知道这一点:

Overrides the name of the character encoding used in the body of this request

这个方法用来设置网页 body 的编码方式,可以在页面中设置,也可以在获取参数之前,通过 HttpSevletRequest 对象设置,现在来看 POST 提交:

POST 表单的编解码

在前面提到了 POST 表单提交的参数的解码是在第一次调用 request.getParameter 发生的, POST 表单参数传递方式与 QueryString 不同,它是通过 HTTP BODY 传递到服务端的。当我们在页面上点击 submit 按钮时浏览器首先将根据 ContentType Charset 编码格式对表单填的参数进行编码然后提交到服务器端,在服务器端同样也是用 ContentType 中字符集进行解码。所以通过 POST 表单提交的参数一般不会出现问题,而且这个字符集编码是我们自己设置的,可以通过 request.setCharacterEncoding(charset) 来设置。

另外针对 multipart/form-data 类型的参数,也就是上传的文件编码同样也是使用 ContentType( 里所说的 ContentType 是指 http 头的 ContentType ,而不是在网页中 meta 中的 ContentType ) 定义的字符集编码,值得注意的地方是上传文件是用字节流的方式传输到服务器的本地临时目录,这个过程并没有涉及到字符编码,而真正编码是在将文件内容添加 parameters 中,如果用这个编码不能编码时将会用默认编码 ISO-8859-1 来编码。

通过上面的分析我们可以知道, post 提交的编码解码跟服务器端的设置没有任何关系,而且也别妄想通过使用 request.setCharacterEncoding() 方法来解决 url 传递参数中文乱码的问题。

C web.xml 中配置了解决中文编码问题的过滤器,我们查看源码发现这个:

  if ( encoding != null && ( forceEncoding || request.getCharacterEncoding() == null ))

        {

            request.setCharacterEncoding( encoding );

            if ( forceEncoding && responseSetCharacterEncodingAvailable )

                response.setCharacterEncoding( encoding );

        }

        filterChain.doFilter(request, response);

看到这个方法没有:

request.setCharacterEncoding( encoding );

现在就知道为什么我配置了中文编码过滤器还是出错的原因了嘛,这个过滤器只会对 post 提交有效,这是防止你在页面中没有设置 ContentType charset 而导致中文乱码。

 

   经过上面的分析总结一下终极解决办法:

1、  Tomcat 中设置 URIEncoding useBodyEncodingForURI 这两个参数。

2、  页面中或 js 中有中文路径或从参数,先进行编码,编码字符集和上面 tomcat 中配置的一样。

 

0
0
分享到:
评论

相关推荐

    系统Email中文乱码的案例分析

    通过本案例分析,我们了解到在Android系统的Email客户端中出现中文乱码问题的原因及解决方法。这不仅有助于改善用户体验,也为开发者提供了一种有效的故障排查思路。在未来的产品开发和维护过程中,应当加强对字符...

    PHP之JPgraph横坐标中文乱码问题

    ### PHP之JPgraph横坐标中文乱码问题解析 在处理PHP与JPgraph图表库时,经常遇到的一个问题是中文字符在横坐标上显示为乱码。本文将深入探讨这一问题,并提供一个具体的解决方案。 #### 问题描述 在使用PHP结合...

    WebSevice 中文乱码

    ### 实践案例分析 在给定的部分内容中,可以看到一些关键代码片段,比如使用`THTTPRIO`对象来处理HTTP请求,并通过`soUTF8InHeader`选项来设置消息头的字符集。这正是解决中文乱码问题的一个重要步骤。然而,仅凭这...

    js出现乱码问题介绍大全

    #### 三、具体案例分析 ##### 3.1 HTML页面中的乱码问题 HTML页面中,可以通过`&lt;meta&gt;`标签来声明页面的字符集。例如: ```html ;charset=UTF-8" /&gt; ``` 但是,如果引用的JavaScript文件没有正确设置字符集,...

    freemarker 中文乱码解决

    在处理Freemarker模板引擎时,中文乱码问题是一个常见的挑战,尤其是在国际化应用中。Freemarker是一款功能强大的模板引擎,被广泛应用于Web开发中,用于动态生成HTML、XML等文本格式的页面。然而,当涉及到非英文...

    处理highcharts导出图片出现中文乱码的问题

    提供的博文链接()可能包含了更具体的解决方案或案例分析。访问该链接获取更多针对性的指导。 在处理"char_jar"这个文件时,如果它是一个包含特定解码方法或工具的Java JAR文件,可能需要进一步了解其内容以确定...

    S22.Imap解决中文乱码问题

    在提供的压缩包“解决邮件乱码问题”中,很可能包含了对S22.Imap源码的具体修改和修复,以及可能的测试案例,以便其他开发者可以直接应用或参考解决类似问题。为了确保兼容性和稳定性,开发者在应用这些修改前,应该...

    java中文乱码分析

    ### Java中文乱码分析 #### 一、概述 在Java Web开发中,中文乱码问题是一个常见的技术难题,尤其在处理HTTP...通过上述分析和建议,我们可以有效地解决Java Web应用中的中文乱码问题,提高系统的稳定性和用户体验。

    php中文乱码问题 初学php最学见的问题

    #### 三、案例分析 根据提供的部分代码示例,可以看出存在几个问题: 1. **未指定HTML文档的字符集**:应该在`&lt;head&gt;`部分添加`&lt;meta&gt;`标签来声明字符集。 2. **未设置PHP脚本的字符集**:在PHP脚本开头应使用`...

    hibernate数据库中文乱码问题

    #### 实际案例分析 假设我们有一个使用MySQL数据库的Java项目,该项目使用Hibernate框架进行数据库操作,并使用Tomcat作为应用服务器。现在遇到了中文乱码的问题,我们可以按照以下步骤进行排查和解决: 1. **检查...

    itext jar包组合-导出word文档案例,解决中文乱码问题

    本文将详细介绍如何使用iText Java库来创建、操作Word文档,并解决中文乱码的问题。 首先,我们需要理解iText库的核心功能。iText是一个开源的Java库,主要用于生成PDF和HTML文档,但通过一些扩展,它也可以用来...

    Oracle客户端PL/SQL 中文乱码解决

    在Oracle数据库环境中,PL/SQL是...文档《Oracle客户端中文乱码解决.docx》应该包含了详细的操作指南和案例分析,建议参考文档内容进行具体操作。在解决乱码问题时,保持耐心,仔细排查,通常能够找到合适的解决办法。

    页面中文和后台服务器端接收中文乱码问题完全解决

    ### 页面中文和后台服务器端接收中文乱码问题完全解决 #### 概述 在Web开发过程中,中文乱码问题是常见的技术难题之一。特别是在早期的Web应用程序中,由于编码标准不统一,不同系统间的编码方式差异等原因,导致...

    解决java所有中文乱码集合

    在Java编程语言中,中文乱码是一个常见的问题,特别是在处理文本输入、输出或者网络传输时。本集合旨在全面解析和解决各种中文乱码问题,帮助开发者有效地理解和应对这类问题。 一、乱码产生的原因 1. 编码与解码...

    j2ee项目中中文乱码问题集锦

    本文将围绕一个典型的案例来详细分析如何解决J2EE项目中的中文乱码问题,并总结出一系列实用的方法。 #### 一、问题背景与原因分析 在J2EE应用中,中文乱码主要出现在以下几个环节:用户输入数据时、服务器处理...

    jsp中文乱码的解决方案

    实际案例分析 文档《JSP各种乱码的处理(一).doc》和《JSP各种乱码的处理(二).doc》中可能详细列举了各种JSP乱码问题的实例及解决方法,包括但不限于文件上传、读取流、数据库操作等方面,建议参考学习,以便更全面...

    FlashFXP中文乱码解决方案

    #### 四、案例分析 假设在一个开发团队中,成员A通过FlashFXP向远程服务器上传了一个包含中文字符的配置文件,但发现文件上传后出现了乱码问题。此时可以按照以下步骤排查问题: 1. **检查FlashFXP设置**:确认...

    Java乱码问题解决

    #### 三、案例分析 假设我们有一个简单的JSP页面`test.jsp`,用于测试客户端提交数据时的乱码问题。页面顶部已设置了正确的字符集: ```jsp ;charset=GBK" %&gt; ``` 页面内容如下: ```jsp String str = request....

    关于MyEclipse5.5合成SSH后出现中文乱码的问题解决方法之一

    进一步分析发现,使用MyEclipse 6.5重新生成Hibernate和Spring的配置后,中文乱码问题得到了解决。这暗示了问题可能源于MyEclipse 5.5生成的SSH配置包与6.5版本的不同。开发者列出了两个版本生成的SSH包,发现5.5...

Global site tag (gtag.js) - Google Analytics