JAVA中文字符编码问题详解(2)(转)_colin_i的博客-程序员宝宝

技术标签: Java编码 java乱码 中文乱码  Java  

四、JSP读取request.getParameter里的中文参数后,在页面显示为乱码。
 
  在JAVA的WEB应用中,对request对象里的parameters的中文处理一直是常见也最难搞的一只大怪兽。经常是刚搞定了这边,那边又出了乱码。而导致这种复杂性的,主要是此过程中字符编解码次数非常多,而且无论是浏览器还是WEB服务器特别是TOMCAT总是不能给我们一个比较满意的支持。
  首先我们来分析用GET方式上传参数的乱码情况。
  例如我们在浏览器地址栏输入以下URL:http://localhost:8080/test/test.jsp?param=大家好
  我们的JSP代码如此处理param这个参数:
  <% String text = request.getParameter("param");  %>
  <%=text%>
  而就这么简单的两句代码,我们很有可能在页面上看到这样的乱码:´ó¼ÒºÃ
  网上对处理request.getParamter中的乱码有很多文章和方法,也都是正确的,只是方法太多让人一直不明白到底是为什么。这里给大家分析一下到底是怎么一回事。
  首先,我们来看看与request对象有哪些相关的编码设置:
  1. JSP文件的字符编码
  2. 请求这个带参数URL的源页面的字符编码
  3. IE的高级设置中的选项“总以utf-8方式发送URL地址”
  4. TOMCAT的server.xml中配置URIEncoding
  5. 函数request.setCharacterEncoding()
  6. JS的encodeURIComponent函数与JAVA的URLDecoder类
这么多条相关编码设置,也难怪大家被搞得头晕了。这里给大家根据各种情况给大家一一分析一下。见下表:


  

  由这个表我们可以看到,IE的“总以utf-8方式发送URL地址”设置并不影响对parameter的解析,而从页面请求URL和从地址栏输入URL居然也有不同的表现。
  根据这个表列出的现象,大家只要用smartSniff抓几个网络包,并稍稍调查一下TOMCAT的源代码,就可以得出以下结论:
  1. IE设置中的“总以utf-8方式发送URL地址”只对URL的PATH部分起作用,对查询字符串是不起作用的。也就是说,如果勾选了这个选项,那么类似http://localhost:8080/test/大家好.jsp?param=大家好这种URL,前一个“大家好”将被转化成utf-8形式,而后一个并没有变化。这里所说的utf-8形式,其实应该叫utf-8+escape形式,即%B4%F3%BC%D2%BA%C3这种形式。
  那么,查询字符串中的中文字符,到底是用什么编码传送到服务器的呢?答案是系统默认编码,即GBK。也就是说,在我们中文操作系统上,传送给WEB服务器的查询字符串,总是以GBK来编码的。
  2. 在页面中通过链接或location重定向或open新窗口的方式来请求一个URL,这个URL里面的中文字符是用什么编码的?答:是用该页面的编码类型。也就是说,如果我们从某个源JSP页面上的链接来访问http://localhost:8080/test/test.jsp?param=大家好这个URL,如果源JSP页面的编码是UTF-8,则大家好这几个字的编码就是UTF-8。
  而在地址栏上直接输入URL地址,或者从系统剪贴板粘贴到地址栏上,这个输入并非从页面中发起的,而是由操作系统发起的,所以这个编码只可能是系统的默认编码,与任何页面无关。我们还发现,在不同的浏览器上,用链接方式打开的页面,如果在地址栏上再敲个回车,显示的结果也会不同。IE上敲回车后显示不变化,而傲游上可能就会有乱码或乱码消失的变化。说明IE上敲回车,实际发送的是之前记忆下来的内存中的URL,而傲游上发送的从当前地址栏重新获取的 URL。
  3. TOMCAT的URIEncoding如果不加以设置,则默认使用ISO-8859-1来解码URL,设置后便用设置了的编码方式来解码。这个解码同时包括PATH部分和查询字符串部分。可见,这个参数是对用GET方式传递的中文参数最关键的设置。不过,这个参数只对GET方式传递的参数有效,对POST 的无效。分析TOMCAT的源代码我们可以看到,在请求一个页面时,TOMCAT会尝试构造一个Request对象,在这个对象里,会从 Server.xml里读取URIEncoding的值,并赋值给Parameters类的queryStringEncoding变量,而这个变量将在 解析request.getParameter中的GET参数时用来指导字符解码。
  4. request.setCharacterEncoding函数只对POST的参数有效,对GET的参数无效。且这个函数必须是在第一次调用 request.getParameter之前使用。这是因为Parameters类有两个字符编码参数,一个是encoding,另一个是 queryStringEncoding,而setCharacterEncoding设置的是encoding,这个是在解析POST的参数是才用到 的。
  所以,这就导致了我们通常都要分开处理POST和GET的字符编码,用TOMCAT自带的filter只能处理POST的,另外要设置URIEncoding来设置GET的。这样很麻烦而且URIEncoding无法根据内容来动态区分编码,总还是一个问题。
  在调查TOMCAT的代码时发现了另一个在server.xml里的参数useBodyEncodingForURI,可以解决这个问题。这个参数设成 true后,TOMCAT就会用request.setCharacterEncoding所设置的字符编码来同样解析GET参数了。这样,那个 SetCharacterEncodingFilter就可以同时处理GET和POST参数了。
 
  知道了以上知识后,我们再来分析一下前面表格中列出的几个典型现象。
  第一条,请求源页面的编码为UTF-8,而TOMCAT的URIEncoding未指定,则TOMCAT用ISO8859-1方式来解码参数,所以从request中读出来后,内存中存储的为错误的UNICODE数据,导致之后到屏幕显示的所有转换全部出错。
  第九条,请求源页面编码为GBK,而TOMCAT的URIEncoding也为GBK,TOMCAT用GBK方式去解码原本用GBK编码的字符,解码正确,内存中的UNICODE值正确,最终显示正确的中文。
  第十三条,请求源页面编码为UTF-8,TOMCAT的URIEncoding也为UTF-8,而在IE6中最终显示的中文字符,如果是奇数个数,则最后一个会显示为乱码。这是为什么呢?
  我的猜测是,这是因为IE6将URL地址发送时,对查询字符串是直接对UTF-8格式的字符使用GBK来编码,而不是对UNICODE的字符来用GBK编 码,所以UTF-8的数据没有经过UNICODE而直接编码成了GBK。而到了TOMCAT这边,GBK的编码又被当成UTF-8做了解码。所以这个过程 中经过了UTF-8转换成GBK,然后又从GBK转换成UTF-8的过程,而这种转换,恰好就会出现奇数个中文字符串的最后一位为乱码的现象。而在IE7 中,估计把这种现象当做BUG已经被解决了,即在发送地址时会先转成UNICODE再编码成GBK。那么估计在IE7的浏览器+中文操作系统环境下,如果 我们把TOMCAT的URIEncoding设置成GBK,无论JSP编码成什么格式,都不会出现乱码。这个没测试,请大家自己验证。
  其他几条就不再做分析了,有兴趣的大家自己分析。
   

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/colin_i/article/details/84630364

智能推荐

MPI_lamboot是什么_nhczp的博客-程序员宝宝

MPI 文档站 http://www-unix.mcs.anl.gov/romio/摘要: 什么是MPI,如何用?什么样的人应该使用MPI?怎样从MPI的开源实现中来学习MPI的一些基本的东西。消息传递接口(Message Passing Interface)“MPI”这个词经常在和高性能计算相关的讨论中出现。有时候人们是喜爱的,有时候是蔑视的,而跟多的时候这是一个让疑惑的词。这篇文章

TCP 和 UDP 的区别_udp和tcp的主要区别_[Object object]的博客-程序员宝宝

前言UDPTCPTCP 的三次握手TCP 四次挥手累计确认顺序问题和丢包问题流量控制的问题拥塞控制的问题总结及面试问题前言前端的面试中经常问的 TCP 和 UDP 的区别,网上也有好多内容,比如 TCP 和 UDP 的区别TCP 是面向连接的,UDP 是面向无连接的UDP程序结构较简单 TCP 是面向字节流的,UDP 是基于...

Codeforces 题目集锦_G·Dking的博客-程序员宝宝

我的CF账号:guozexin如果题解有哪些疑惑的地方,可以直接在CF上找我的代码查看细节1601A这道题目乍一看很花哨,但和位运算有关的题目,手玩一下就可以把原题的操作换作一个很简单的操作。本题中其实就是在同一位上选择k个1,使这k个1都变成0,若要使一位上的1都变成0,那这一位上1的个数需是k的倍数,所以我们对每一位上的1的个数取gcd,得到k,若k成立,则k的因数也一定成立,输出k的所有因数即可1601B※青蛙爬井问题在初学OI时也有一道这样的青蛙爬井的题目,当时a和b都是固定的,推出数

基本面分析与技术分析 _技术分析和基本面分析_NNeter的博客-程序员宝宝

 股票投资分析方法通常可以分为两大类:基本面分析和技术分析。投资者经常争论哪一种方法更好。本课中将讨论为什么两种方法对成功投资都至关重要。 如何看待基本面分析和技术分析之争? 就我个人的经验,这并不是一个非此即彼的问题。在分析的时候,你必须对这两个方面都作出考虑。一方而,要运用基本面分析的方法考虑公司的竞争力、经营情况、产品和技术情况,另一方面,也要运用技术分析的方法来判断该股票当前的市场表现。基

IMU惯导相关开源项目整理_kf-gins_路痴导航员的博客-程序员宝宝

这篇博客主要是整理一下我知道、或者用过的惯导相关的比较好的开源项目。好的开源项目让我们站在巨人的肩膀上,感谢开源作者们的无私,也欢迎各位读者分享其他优秀的开源项目,我们一起学习,共同进步。

随便推点

WebSocket 基于OkHttps搭配Stomp实现客户端的监听_websocket客户端监听_一个小浪吴啊的博客-程序员宝宝

Stomp#添加依赖#要开启 Stomp 功能,需要添加以下依赖:Maven#&lt;dependency&gt; &lt;groupId&gt;com.ejlchina&lt;/groupId&gt; &lt;artifactId&gt;okhttps-stomp&lt;/artifactId&gt; &lt;version&gt;3.4.5&lt;/version&gt;&lt;/dependency&gt;Gradle#implementation 'co

es6 对象的扩展_一只小白菜~的博客-程序员宝宝

对象的扩展传统对象属性写法es6对象属性写法属性名表达式属性的可枚举性和遍历`可枚举型`四个操作会忽略enumerable为false的属性:`属性的遍历`以上属性遍历的次序规则Object. is()Object.assign()Object.setPrototypeOf()Object.getPrototypeOf()Object.keys()Object.values()Object.ent...

电脑打不开u盘,总显示“本次操作由于这台计算机的限制而被取消,请与您的系统管理员联系”-程序员宝宝

1.win+R唤起run窗口输入regedit2.打开第二个文件HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies最后一个文件中两个文件Comdlg32和Explorer,删除所有NO开头并且是1结尾(145)也可以删删除后U盘就能正常打开。...

R语言删除包含NA的列_r语言删除na值_upuil的博客-程序员宝宝

测试数据如下:Itun &lt;- data.frame(v1 = c(1,1,2,1,2,1), v2 = c(NA, 1, 2, 1, 2, NA)) Itun[ , colSums(is.na(Itun)) == 0]output:[1] 1 1 2 1 2 1另一种方式:Itun[ , apply(Itun, 2, function(x) !any(is.na(x)))]output:[1] 1 1 2 1 2 1参考点这里...

GC--原理和常见回收算法_海是倒过来的天~的博客-程序员宝宝

一.   原理GC是垃圾收集的意思(Garbage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。简而言之,GC是将java的无用的堆对象进行清理,释放内存,以免发生内存泄露二 .   常见回收算法...

2020 关于Map Map<String,String> Map<String,Object>的简单使用_map<string,object>用法_AlikeLin的博客-程序员宝宝

关于Map Map&lt;String,String&gt; Map&lt;String,Object&gt;的简单使用map很全面,可用于返回从conytoller给前段需要的信息或字段,甚至不需要定义返回结果集的类了前段定义需要的msg等等。。。

推荐文章

热门文章

相关标签