Java Web乱码分析及解决方式(一)——GET请求乱码

Java Web乱码分析及解决方式(一)——GET请求乱码

大家好,又见面了,我是全栈君。

引言:

    在进行Web開始时。乱码是我们最常常遇到也是最主要的问题。有经验的程序员非常easy能解决,刚開始学习的人则easy被泥潭困住。

并且非常多时候。我们即使攻克了乱码问题也是不明就里。往往云里雾里。

    事实上乱码问题非常easy,就是client和server使用了不一样的字符集导致的。也就是我们发送文件时用的字符编码和解析文件的编码不一致。所以仅仅要搞清楚了我们的文件是怎么被编码和解码的解决乱码就非常easy了。分析乱码,我们从请求乱码和响应乱码来分析,请求乱码又须要依据GET和POST来单独分析。

 

请求乱码——GET

    请求的编码是由浏览器发出的。使用GET方法请求server信息时。依据HTTP协议规定,Request包是没有请求体的(也就是Request Body不存在)。所以我们仅仅能把请求參数放在URL中。因此使用GET方式与server通信,编码方面我们关心的重点是浏览器对URL的编码方式,和server对URL的解码过程。

关于URL

    URL是我们常常接触并不是常简单的一种技术,URL技术简单到它事实上就是一个字符串。

实际上URL的结构是非常复杂的,仅仅只是通常上使用方法比較简单而已。关于URL的具体介绍能够參考以下的文章:

我是传送门!。!大笑

Java Web乱码分析及解决方式(一)——GET请求乱码

    URL的规范定义在RFC 1738文档中。通过URL我们能够获得通信协议、主机域名、处理port、应用路径、路径參数、查询參数、页面片段等信息。

比方:

    http://user:pass@example.com/a/b;q=1/c?d=2;sessionid=qewfewrwer#2

    依据上面的URL。我们能够得到例如以下信息:

Part

Data

serverAPI

Scheme

http

用req.getScheme

user

user

囧,不知道

pass

pass

囧,不知道

host address

example.com

req.getServerName

port

80

req.getServerPort

path

/a/b;q=1/c

req.getContextPath

query parameters

d=2;sessionid=qwefewrwer

req.getQueryString

fragement

2

 

 

    开发时,我们经经常使用到的就是path和query parameters。这两个參数,剩下的參数使用的比較少。只是在RESTful API中,像路径參数的信息可能会用到。fragement用来在页面内进行锚点定位。(已经非经常见了)


浏览器对Path部分的编码

    path信息被用来匹配处理路径。一般设计上非常少在path中包含中文參数。RFC文档对于path的编码也没有明白规定。可是据其它文章的介绍。浏览器对Path的编码一般都会採用UTF-8编码,最新的URI标准已经定义了URI的编码採用UTF-8编码。

    定义:简单说path部分就是应用路径部分,就是URL去掉协议、域名、port和查询信息剩下的部分。


server对Path部分的解码:(三种方案)

    通常上,我们的请求都会首先发给Web容器(以下以Tomcat为例),URL也会被Web容器解码,对于Tomcat容器来说,我们能够在conf/server.xml的connector标签中添加URL解码參数,默认容器对URL的使用ISO-8859-1解码。

<Connector port="8080" protocol="HTTP/1.1"
         connectionTimeout="20000"
         redirectPort="8443" />

    上面的是Tomcat的默认设定,能够给标签加入URIEncoding属性来指定URL的解码方案。PS:标签写法是URI不是URL)

    假设不想使用这样的硬解码方案。还能够指定还有一个属性:useBodyEncodingForURI,这个属性用来告诉Web容器。假设request指定了解码方案,则使用request.setCharacterEncoding指定的编码来解码URL。

另外一种方案没有经过測试。假设有须要能够尝试下。

具体资料能够參考以下的Tomcat官方文档:

http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q2

    此外。假设不想改动容器的全局配置。毕竟有时候容器里可能不止我们一个应用,那么我们还能够採用以下的做法来提取參数

String path = req.getServerPath();//自己手动提取,不适合配合框架
path = new String(path.getBytes(“ISO8859-1”,”UTF-8”));//又一次拼装


    
上面的做法。我们要确定Web容器对URL的解码用的是ISO8859-1,由于不排除其它人改动了容器配置或容器配置本身比較奇葩的可能。

 

浏览器对QueryParameter的编码

    查询參数和Path是不一样的,缺少查询參数,web容器是能够定位到我们的处理程序的,可是缺少path就不行。

另外,path和查询參数的保留字符是不一样的。

    定义:简单来说查询參数就是path后面紧跟的?后面的部分,用&来连接各个查询參数。

    因为Path和查询參数的不同,有些浏览器对查询參数的编码和path部分的编码是不一致的。

详细使用怎么编码的比較混乱。能够參考下以下的文章:

又一个传送门,啦啦啦!

安静

    依据上面的文章总结的规律:

    (1)Path部分或者说除查询參数外的URL部分。各浏览器用UTF-8编码;

    (2)查询參数,各浏览器依据操作系统编码决定;

    上面的文章比較老了,规律可能不有用了,可是也能说明一定问题。对于某些文章说的,查询參数会依据页面编码来决定,我没有做实验。可是这样的结论肯定是片面的。原因例如以下:

    页面的meta參数是用来向浏览器说明页面编码的,其次。在使用POST Method发送数据的时候,浏览器会依据meta的编码来编码Request Body。而Get方式。我们在没有页面的时候也能够发起。所以浏览器根本找不到Meta标签,也就没法參考页面编码。

    浏览器对查询參数究竟使用哪种方式编码的,我没有找到专业、权威、可信的答案,可是我觉得这个还是详细情况详细分析。做个小实验即可了。

毕竟时代在进步。厂商们统一使用UTF-8编码的可能性比較大。并且后面有不依赖浏览器编码的解决方式。

 

server对QueryParameter的解码

    查询參数也是URL的一部分。所以Web容器对查询參数的解码比較明智,解码和path使用的是一样的方案的编码,所以解决方式也是一样的。


出现乱码:

    在处理查询參数时,我们经常使用req.getParameters();来获取某个參数。这种方法背后非常少有人关心它的工作原理。并且也不是必需。

这一部分是最easy出现乱码的,毕竟它里面的參数可能是用户输入的,并非我们设计的。

在GET方式下,出现这样的乱码不要慌张,首先我们要分析出,浏览器对查询參数究竟採用了哪种编码。

方法简单(也复杂),chrome下F12打开开发人员工具

Java Web乱码分析及解决方式(一)——GET请求乱码

Java Web乱码分析及解决方式(一)——GET请求乱码

   找到network标签,能够看到Request URL中显示的是k= %E4%B8%AD%E5%9B%BD,把%去掉,能够得到6个16进制数,百度下unicode码表。能够看到他们正好是“中”和“国”的unicode编码。所以能够推測浏览器使用的是UTF-8编码。这样的推断方式须要对字符编码比較熟悉。只是也不算非常难,找点字符编码的文章学学非常easy就能看出规律来。

    PS:不要通过浏览器的地址栏看URL编码,非常多浏览器的地址栏会对URL解码显示。

    之后,server端,首先确定下。你的Web容器对URL使用的解码方案,然后对应的选择String(param.getBytes(“ISO8895-1”,”UTF-8”))或者是useBodyEncodingForURI、URIEncoding方案就好了。


总结:

       使用GET方式出现乱码时,最基本的是找出浏览器对URL的编码方式,假设使用JS编程时。在浏览器能够使用encodeURIComponent函数对中文參数进行编码后再拼装參数。Java端使用URLDecoder.decode方法解码。JS端要进行两次编码,否则第一次的URL编码会被Web容器解码,获取的參数仍有可能是乱码。能够參考:

传送。!!!!

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/115225.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • JS中鼠标拖拽div(2)(setCapture()方法和releaseCapture()方法)

    JS中鼠标拖拽div(2)(setCapture()方法和releaseCapture()方法)接着鼠标拖拽div(1)解决问题,当在拖拽事件所在的页面按下键盘的ctrl+A全选后,再去拖拽div,浏览器会默认去搜索网页中的内容,拖拽功能就会失效,(搜索网页内容是浏览器的默认行为,所以要想不发生这种情况,就得将其取消,是谁执行之后触发了浏览器的默认行为,就在谁里面returnfalse即可取消浏览器的默认行为,但这种方式ie8及以下的版本不支持。)在ie8及以下版本浏览器中,如果调用了元素的setCapture()方法,那么点击任何事物都会来执行这个元素绑定的响应函数。例如:btn.oncl

    2022年5月8日
    54
  • LAN8720A网络模块的使用问题

    LAN8720A网络模块的使用问题一、LAN8720A模块驱动电路最近在调试STM32F4驱动LAN8720A网络模块,在做方案前参考是正点原子的LAN8720A的驱动电路方案,但是从网上买回来的LAN8720A模块用正点原子的例程一直驱动不起来,在windows系统下一直都ping不通,后面对比正点原子的LAN8720A与网上买回来的微雪LAN8720A模块的电路有差异。下图为网上买回来微雪的LAN8720A驱动电路:下…

    2022年6月15日
    370
  • Nginx 配置中nginx和alias的区别分析

    Nginx 配置中nginx和alias的区别分析root和alias都可以定义在location模块中,都是用来指定请求资源的真实路径,比如:?123location/i/{root/data/w3;}请求http://foofish.net/i/top.gif这个地址时,那么在服务器里面对应的真正的资源是/data/w3/i/top.gif文件注意:真实的路径是root指定的值加上location指定的值。而alias正…

    2022年7月14日
    52
  • mock测试概念「建议收藏」

    mock测试概念「建议收藏」mock测试概念:mock是在测试过程中,对于一些不容易构造/获取的对象,创建啊一个mock对象来模拟对象的行为mock对象使用范畴真实对象具有不可确定的行为。真实对象很难被创建。真实对象的某些行为很难触发。真实情况令程序运行速度很难。真实对象实际上并不存在。测试隔离的实现。mock有什么用?解除一些依赖关系,当测试部分接口实现,需要依赖于与其他接口与,而其他接口没完…

    2022年6月20日
    25
  • ZPL指令_TSC指令

    ZPL指令_TSC指令^CC,~CC改变格式指令前缀  ^CC,~CC(改变脱字符)指令是用于改变指令前缀。缺省前缀是脱字符(^)。^CC,~CC指令格式  ^CCx,~CCx^CC,~CC=改变脱字符x=任何ASCII字符  缺省值:要求有参数。如不用参数,下一字符接收后作为新的前缀字符。

    2025年7月27日
    5
  • ipset常用命令

    ipset常用命令ipset设置安装#yuminstallipset创建ipset黑名单(黑名单名称为blacklist)#ipsetcreateblacklisthash:iptimeout259200hashsize4096maxelem1000000查看列表#ipsetlistblacklist向黑名单中添加IP/端口#ipsetaddbl…

    2022年10月7日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号