`
yaomeone
  • 浏览: 60185 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

url中文乱码分析

    博客分类:
  • 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);

    }

 

从上面的代码中可以知道对 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 中配置的一样。

分享到:
评论

相关推荐

    URL汉字编码问题(及乱码解决)

    URL汉字编码问题是Web开发中一个常见的问题,特别是在处理中文网址时。根据RFC 1738,URL只能使用英文字母、阿拉伯数字和某些标点符号,不能使用其他文字和符号。因此,如果URL中有汉字,就必须编码后使用。但是,...

    html 中文乱码 HTML超链接中文乱码问题分析及解决方法

    如果直接拼接,传到后台Action的参数对象中后取出会是乱码,需要编码后再拼接到URL上。 解决方法是在Action中添加一个成员变量,保存编码后的中文参数。在vm页面渲染时取出这个变量值,再拼接超链接。 在这里碰到的...

    java中文乱码解决问题

    下面我们对容易产生乱码问题的场景进行分析,并提出解决方案。 1. 以 POST 方法提交的表单数据中有中文字符 在 Servlet/JSP 程序中,通过请求对象的 getParameter() 方法得到的字符串是以 ISO-8859-1 转换而来,这...

    PHP基于curl post实现发送url及相关中文乱码问题解决方法

    主要介绍了PHP基于curl post实现发送url及相关中文乱码问题解决方法,结合具体实例形式分析了php使用curl实现post数据发送及content-type相关设置操作技巧,需要的朋友可以参考下

    jquery获取URL中参数解决中文乱码问题的两种方法

    从A页面通过url传参到B页面时,解析url参数可以用下面两种方法: 方法一:正则分析法 代码如下: function getQueryString(name) { var reg = new RegExp(“(^|&)” + name + “=([^&]*)(&|$)”, “i”); var r = ...

    .Net获取URL中文参数值的乱码问题解决方法总结

    主要介绍了.Net获取URL中文参数值的乱码问题解决方法,总结分析了针对URL参数传递中出现的乱码问题与相应的解决方法,具有一定参考借鉴价值,需要的朋友可以参考下

    asp.net乱码解决方法

    仔细分析后,觉得还是第4种方法最适合解决当前问题,把中文参数进行如4中的操作。但又出现另外一个问题,由于这是一个用户可以自由输入链接地址的功能,所以首先要做的就是得先分析这些链接URL,解析出参数,再...

    如何解决JQuery ajaxSubmit提交中文乱码

    url: "ajaxsub.aspx?abc=test", type: "post", dataType: "json", success: data }); 分析:JQuery的AJAX提交,会将要提交的数据进行编码,使用encodeURIComponent在js中处理数据。因此,无论是 Firefox或者IE,提交...

    JS对URL字符串进行编码/解码分析

    例如:发送页与接受页的编码格式(Charset)不一致(假设发送页面是GB2312而接收页面编码是 UTF-8),使用escape()转换传输中文字串就会出现乱码问题。 以下是JS下对URL进行编/解码的各种方法: escape 方法:返回一个...

    实验报告5 http协议.doc

    进入一个学校的新闻首页,分析各不同新闻网页url之间的区别和联系,并根据得到的规律通过程序生成所要请求的...对生成的文件进行验证,如果出现中文乱码的问题,请对可能的原因进行分析,并给出可行的解决方案。

    python网络编程之http协议-数据请求

    对于每个获取的网页数据,分别将其写入到本地相应的html文件中,要求本地网页数据文件的文件名为pageXXX(XXX为请求页面的编号) 对生成的文件进行验证,如果出现中文乱码的问题,请对可能的原因进行分析,...

    BeautifulSoup

    通常用来分析爬虫抓取的web文档。 注意:为了解决乱码问题,用版本3的。如3.2.1。BeautifulSoup处理后的默认编码是utf-8。 中文文档:http://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html 其他...

    1234阿塞企业网站系统

    //乱码转换成中文 Statement stmt = conn.createStatement(); //建立Statement的实例,相当于创建一个查询分析器的运行环境 sql = "insert department values('" + request.getParameter("depName") + "')"; if ...

    CheerpJ Applet Runner-crx插件

    语言:English 在不安装Java的情况下运行Java小程序 ...此扩展程序使用Google Analytics(分析)来跟踪使用情况。 IP,URL或cookie永远不会被记录。 您可以在扩展程序“设置”面板下选择退出任何形式的跟踪。

    使用nodejs下载风景壁纸

    superagent-charset (手动指定编码,解决GBK中文乱码) cheerio express async (并发控制) 完整的代码,可以在我的github中可以下载。主要的逻辑逻辑在 netbian.js 中。 以彼岸桌面(http://www.netbian.com/)...

    HttpClient以及获取页面内容应用

    2.3.1获取内容中文乱码 /** * 通过url获取网页内容, * 解决中文乱码问题 * @param httpUrl * @return */ public static String downloadPage(String httpUrl) { StringBuffer pageBuffer = new ...

    Discuz! X1.5.1 简体GBK R20111221.zip

    FIX 设置主题标签,utf-8编码时的乱码bug FIX 去掉'wmode', 'transparent'属性,在IE9下面会造成没有办法输入文字的问题 FIX 修复QQ互联用户登录覆盖发帖同步设置的bug FIX 群组发帖审核时间段不受全局限制 FIX ...

Global site tag (gtag.js) - Google Analytics