jsp

位置:IT落伍者 >> jsp >> 浏览文章

如何解决JSP参数传递乱码


发布日期:2023年08月30日
 
如何解决JSP参数传递乱码

计算机生于美国英语是他的母语而英语以外的其它语言对他来说都是外语他跟我们一样不管外语掌握到什么程度也不会像母语那样使用得那么好时常也会出一些“拼写错误”问题

乱码的出现根本原因在于编码和解码使用了不同的编码方案比如用GBK编码的文件用UTF去解码结果肯定都是火星文所以要解决这个问题中心思想就在于使用统一的编码方案

jsp页面间的参数传递有以下几种方式表单(form)的提交直接使用URL后接参数的形式(超级链接)如果两个jsp页面在两个不同的窗口中并且这两个窗口是父子的关系子窗口中的jsp也可以使用javascript和DOM(windowopenerXXXvalue)来取得父窗口中的jsp的输入元素的值下面就前两种方式中出现的乱码问题做一下剖析

表单(form)的提交实现参数页面间的传递

在介绍表单传递参数的内容之前先来了解一些预备知识表单的提交方式和请求报文中对汉字的处理

表单的提交方式

通常使用的表单的提交方式主要是post和get两种两者的区别在于post方式是把数据内容放在请求的数据正文部分没有长度的限制get方式则是把数据内容直接跟在请求的头部的URL后面有长度的限制下面是同一个页面两种方式的请求报许文

Requesttestjsp代码

  1. <%@pagelanguage="java"contentType="text/html;charset=UTF"
  2. pageEncoding="UTF"%>
  3. <!DOCTYPEhtmlPUBLIC"//WC//DTDHTMLTransitional//EN""
  4. <html>
  5. <head>
  6. <metahttpequiv="ContentType"content="text/html;charset=UTF">
  7. <title>Inserttitlehere</title>
  8. </head>
  9. <body>
  10. <%post方式提交表单%>
  11. <formaction="
  12. UserName:<inputtype="text"name="username"/>
  13. Password:<inputtype="password"name="password"/>
  14. <inputtype="submit"value="Submit">
  15. </form>
  16. </body>
  17. </html>

  1. <%@pagelanguage="java"contentType="text/html;charset=UTF"pageEncoding="UTF"%><!D
  2. OCTYPEhtmlPUBLIC"//WC//DTDHTMLTransitional//EN""
  3. itle>Inserttitlehere</title></head><body><%post方式提交表单%><formaction=":<inputtype="text"nam
  4. e="username"/>Password:<inputtype="password"name="password"/><inputtype="submit"va
  5. lue="Submit"></form></body></html>

在上面的请求页面的username输入框里输入的是“世界杯”三个汉字password输入框中输入""后按下Submit按钮提交请求截获到的请求报文如下

Post方式的请求报文代码

  1. POST/EncodingTest/requestresultjspHTTP/
  2. Accept:image/gifimage/jpegimage/pjpegimage/pjpegapplication/xshockwaveflashapplicati
  3. on/vndmsexcelapplication/vndmspowerpointapplication/msword*/*
  4. Referer:
  5. AcceptLanguage:zhcn
  6. UserAgent:Mozilla/(compatible;MSIE;WindowsNT;Trident/;CIBA;affkingsoftci
  7. ba;NETCLR)
  8. ContentType:application/xwwwformurlencoded
  9. AcceptEncoding:gzipdeflate
  10. Host:localhost:
  11. ContentLength:
  12. Connection:KeepAlive
  13. CacheControl:nocache
  14. username=%E%B%%E%%C%E%D%AF&password=
  15. POST/EncodingTest/requestresultjspHTTP/Accept:image/gifimage/jpegimage/pjpegimage/pjp
  16. egapplication/xshockwaveflashapplication/vndmsexcelapplication/vndmspowerpointapplicati
  17. on/msword*/*Referer::zhcnUs
  18. erAgent:Mozilla/(compatible;MSIE;WindowsNT;Trident/;CIBA;affkingsoftciba;N
  19. ETCLR)ContentType:application/xwwwformurlencodedAcceptEncoding:gzipdeflateH
  20. ost:localhost:ContentLength:Connection:KeepAliveCacheControl:nocacheusername=%E
  21. %B%%E%%C%E%D%AF&password=

以上报文内容可以看出post方式的请求报文是有专门的数据部的

下面的同一请求页面的get提交方式的请求报文

Get方式的请求报文代码

  1. GET/EncodingTest/requestresultjsp?username=%E%B%%E%%C%E%D%AF&password=H
  2. TTP/
  3. Accept:image/gifimage/jpegimage/pjpegimage/pjpegapplication/xshockwaveflashapplica
  4. tion/vndmsexcelapplication/vndmspowerpointapplication/msword*/*
  5. Referer:
  6. AcceptLanguage:zhcn
  7. UserAgent:Mozilla/(compatible;MSIE;WindowsNT;Trident/;CIBA;affkingsoftcib
  8. a;NETCLR)
  9. AcceptEncoding:gzipdeflate
  10. Host:localhost:
  11. Connection:KeepAlive
  12. GET/EncodingTest/requestresultjsp?username=%E%B%%E%%C%E%D%AF&passwo
  13. rd=HTTP/Accept:image/gifimage/jpegimage/pjpegimage/pjpegapplication/xshockw
  14. aveflashapplication/vndmsexcelapplication/vndmspowerpointapplication/msword*/*Refer
  15. er::zhcnUserAgent:Mozi
  16. lla/(compatible;MSIE;WindowsNT;Trident/;CIBA;affkingsoftciba;NETCLR
  17. )AcceptEncoding:gzipdeflateHost:localhost:Connection:KeepAlive

以上报文内容可以看出get方式的请求报文没有专门的数据部数据是直接跟在url的后面

请求报文中对汉字的处理

从上面两种报文可以看出页面上输入的“世界杯”三个汉字被替换成了"%E%B%%E%%C%E%D%AF”这样一个字符串然后发给服务器的看到这可能会有两个问题问题一这个字符串是什么?问题二为什么要做这样的替换?

这个字符串是“世界杯”这三个汉字对应的"UTF”编码"EBECEDAF"在每个字节前追加一个"%"后形成的至于为什么要做这样的转化我的理解是因为请求报文会以"ISO"的编码方式编码后通过网络流的方式传送到服务器端"ISO"仅支持数字英文字母和一些特殊字符所以像汉字等这样的字符"ISO"是不认识的所以就必须先给这些"ISO"不支持的字符做个“整形”手术这样才能正确的将页面上的信息传送到服务器端

这时可能又会有另外一个问题上面的例子中为什么会选用"UTF"编码其它的编码方案可以吗?答案是可以的在jsp页面代码的头部有这样一段代码"<%@ page language="java" contentType="text/html; charset=UTF" pageEncoding="UTF"%>"其中charset的值就是浏览器在提交请求报文前对请求报文做“整形”手术时用的字符集同是也是浏览器解释服务器的响应页面时的字符集

在了解了以上内容后开始剖析表单方式传递参数的乱码问题

以上例为例点击"Submit"按钮后浏览器将做完“整形”手术后的请求报文发送给WEB服务器上的Servlet容器容器在收到这个请求报文后会解析这个请求报文并用这个报文的信息生成一个HttpServletRequest对象然后将这个HttpServletRequest对象传给这个页面所要请求的jsp或Servlet(上例中为"requestresultjsp")在这个被请求的jsp或Servlet(上例中为"requestresultjsp")中使用HttpServletRequest对象的getParameter("")方法来取得上一页面传来的参数默认情况下这一方法使用的是"ISO"来解码所以对于英文或数字的参数值自然能正确取得但对于汉字这样的字符是解不出来的因为那几个汉字曾经做过“整形”手术已经认不出来了要想再把它们认出来那就得要把手术的主刀医生找到然后再做一次“还原”手术下面提供的几个方案可用于不同的情况

方案一代码

  1. <%Stringstr=newString(requestgetParameter("username")getBytes("ISO")"utf");%>
  2. Username:<%=str%>
  3. <%Stringstr=newString(requestgetParameter("username")getBytes("ISO")"utf");%>Usern
  4. ame:<%=str%>

既然requestgetParameter("username")默认情况下返回的字符串是用"ISO"解出来的那就先把这个不可辨认的字符串再用"ISO"来打散也就是requestgetParameter("username")getBytes("ISO")最后再用跟你的页面的charset一致的字符集来重组这个字符串new String(requestgetParameter("username")getBytes("ISO")"utf")这样就能见到它的庐山真面目了

方案一是一种比较万能的方法不管是post还是get都适用但可以看出它的缺点是对于每个可能出现汉字的参数都要显示的做这么一段处理一个两个还行要是很多的话那就应该考虑一下是不是可以选用下一种方案

方案二代码

  1. <%requestsetCharacterEncoding("UTF");%>
  2. <%requestsetCharacterEncoding("UTF");%>

方案二是在页面的最开始或者是在该页面中使用的第一个requestgetParameter("")方法之前加上上述一段代码它的作用是用作为参数传入的编码集去覆盖request对象中的默认的"ISO"编码集这样requestgetParameter("")方法就会用新的编码集去解码因为"UTF"支持中文所以作为参数传过来的“世界杯”三个汉字就能正确的接收到了但关于requestsetCharacterEncoding("")方法API文档中有如下的说明

Overrides the name of the character encoding used in the body of this request This method must be called prior to reading request parameters or reading input using getReader() Otherwise it has no effectb

所以方案二只对post方式提交的请求有效因为参数都在request的body区而对get方式提交的请求则是无效的这时你会发现同样的做法但显示的还是乱码所以你的请求要是是以get方式提交的话那你还是乖乖的选用方案一吧!

从上面的叙述可以知道方案二需要在每个页面的前头加上<%requestsetCharacterEncoding("UTF"); %>这段代码这样做是不是也挺累的所以我们想到了使用过滤器来帮助我们做这件事儿那就清爽简单多了

Encodingfilter代码

  1. publicclassEncodingFilterimplementsFilter{
  2. privateStringcharset;
  3. @Override
  4. publicvoiddestroy(){
  5. //TODOAutogeneratedmethodstub
  6. }
  7. @Override
  8. publicvoiddoFilter(ServletRequestrequestServletResponseresponse
  9. FilterChainchain)throwsIOExceptionServletException{
  10. //用init方法取得的charset覆盖被拦截下来的request对象的charset
  11. requestsetCharacterEncoding(thischarset);
  12. //将请求移交给下一下过滤器如果还有的情况下
  13. chaindoFilter(requestresponse);
  14. }
  15. @Override
  16. publicvoidinit(FilterConfigconfig)throwsServletException{
  17. //从webxml中的filter的配制信息中取得字符集
  18. thischarset=configgetInitParameter("charset");
  19. }
  20. }
  21. publicclassEncodingFilterimplementsFilter{privateStringcharset;@Overridepublicvoiddestr
  22. oy(){//TODOAutogeneratedmethodstub}@OverridepublicvoiddoFilter(ServletRequestreq
  23. uestServletResponseresponseFilterChainchain)throwsIOExceptionServletException{//用init方
  24. 法取得的charset覆盖被拦截下来的request对象的charsetrequestsetCharacterEncoding(thischarset);//将
  25. 请求移交给下一下过滤器如果还有的情况下chaindoFilter(requestresponse);}@Overridepub
  26. licvoidinit(FilterConfigconfig)throwsServletException{//从webxml中的filter的配制信息中取得字
  27. 符集thischarset=configgetInitParameter("charset");}}

要想这个过滤器生效还得到webxml里加入下面的配制信息

Webxml代码

  1. <filter>
  2. <filtername>EncodingFilter</filtername>
  3. <filterclass>cnericencodingtestfilterEncodingFilter</filterclass>
  4. <initparam>
  5. <paramname>charset</paramname>
  6. <paramvalue>UTF</paramvalue>
  7. </initparam>
  8. </filter>
  9. <filtermapping>
  10. <filtername>EncodingFilter</filtername>
  11. <urlpattern>/*</urlpattern>
  12. </filtermapping>
  13. <filter><filtername>EncodingFilter</filtername><filterclass>cnericencodingtestfilterEncodi
  14. ngFilter</filterclass><initparam><paramname>charset</paramname><paramvalue>UT
  15. F</paramvalue></initparam></filter><filtermapping><filtername>EncodingFilter</filt
  16. ername><urlpattern>/*</urlpattern></filtermapping>

直接使用URL后接参数的形式(超级链接)

有些时候可能会遇到通过一个超级链接来把参数传到下一个页面而刚好这个参数的值有可能会出现中文的情况就像下面这样

  1. <ahref="/jstlresultjsp?content=世界杯">GoSouthAfrica

跟form提交有些不同的是当你点击这个超级链接后在浏览器的地址栏里看到的是世界杯而不是%E%B%%E%%C%E%D%AF

这里浏览器并没有帮我们把这个转化工作搞定所以这里要自己动手丰衣足食了做法如下

  1. <ahref="/jstlresultjsp?content=<%=javanetURLEncoderencode("世界杯""utf")%>">GoSouthAfrica

这样的话在第二个页面就能使用

  1. <%Stringstr=newString(requestgetParameter("content")getBytes("ISO")"utf");%>

的方法来正确的得到这个参数值了

总结一下

post提交的方式使用过滤器将到达页面前的request对象中的字符编码设定成跟你页面统一的编码

get提交的方式<%String str = new String(requestgetParameter("content")getBytes("ISO")"utf"); %>这样的字符串重组的方法

超级链接方式先将链接url中的汉字用javanetURLEncoderencode("paramValue""charset")方法处理一下下面的做法参照

上一篇:在Linux系统中搭建JSP开发环境

下一篇:在JSP环境中如何配置和使用fckeditor