http请求(GET/POST)时,url/参数编码的过程分析

http请求(GET/POST)时,url/参数编码的过程分析

这个实验,是在采用ssm框架的基础上演示的。

在前端向后端发出http请求时,有时候当咱们采用GET方式时,参数会被编码在url后面。那么这个url是如何编码解码的呢?前端

http请求的发出,以及编码过程

下面在chrome浏览器和postman下模拟请求,用fiddler来监控请求发出信息。chrome

chrome游览器地址输入:
clipboard.pngjson

这个路径是手动输入的,黑色线是url,黄色线是uri,绿色线是queryString。这时F12,而后咱们路径按下回车后端

chrome地址数组

clipboard.png

chrome监控浏览器

clipboard.png

fiddler监控tomcat

clipboard.png

咱们关注chrome控制台和fiddler的状况,能够发现,chrome发出这个http请求的时候,对查询参数进行了编码。咱们在网站(https://www.bejson.com/conver... 进行Hex转字符的操做,能够发现:中文字符被编码成16进制数,并且每一个字节(byte)的16进制数前都被浏览器加上了一个%。(下图中,20E8B083这4个字节对应“调”,E4BC98这3个字节对应“优”)服务器

clipboard.png

浏览器编码url的风格: 到这里,可能你有点迷惑了。我来解释一下,根据URL的编码规范,浏览器会把URL中的非ASCII字符按照某种编码格式(chrome是utf-8)编码成byte数组后,转成16进制数字,而后在每一个16进制数字前加上%分隔。网络

到如今,应该清楚了浏览器GET传参时的编码过程了。值得一提的是,在实践中,咱们最糟糕也只会在GET方式的url后面携带中文参数,在servletPath(也就是?前的一段)中咱们不会去用中文的,除非你自找麻烦。框架

具体的传输: 其实,咱们尚未讲到url的传输。咱们要知道,在网络世界的传输中,全部的信息都是以字节传输的(byte[]),一个http请求的全部内容都是编码成byte数组后传输的,也就是0101这样的数字。为了方便显示,fiddler中用Hex来表示。能够这么理解,上面那个url路径只是一个初步处理后的string而已,咱们从fiddler中查看,

clipboard.png

咱们对Hex进行几回copy查看:

clipboard.png

能够看出,传输过程当中的Hex数组,就是咱们以前监控到的真正的http请求url通过了中文utf-8编码后的路径。

http请求的接收,以及解码过程

需不须要设置解码呢?

答案是确定的,手动设置一下确定是很是好的。

uri/url的解码过程

下面咱们以tomcat为例,当上面那一大串byte数组传输到服务器后,首先,tomcat会对uri部分进行解码,这里charset由tomcat配置文件中的<Connector URIEncoding="UTF-8"决定,不设置的话默认值为ISO-8859-1。因为域名和端口只会是英文,好比说:www.baidu.com,www.google.com;同时咱们上面讲过,在uri部分咱们不会去用中文,咱们只会采用英文。所以,对于url这一块,不管是采用UTF-8仍是ISO-8859-1解码,url这部份内容都不会乱码。到这一步,咱们服务器端就解码获得了localhost:8082/article/queryByTitle

queryString的解码过程

上面,咱们知道了uri/url这一块的内容解码过程。下面,咱们来看看queryString这部分的解码过程。

咱们在chrome中,F12查看http请求的详细信息,能够发现查询参数被做为parameters保存了下来。这里,能够告诉你们,经过GET方式发出http请求所携带的queryString以及经过POST方式发出http请求所携带的表单参数,也就是GET、POST这2种方式携带的参数,都会被做为parameters保存;在服务器端经过request.getParameter()方法能够获取到值。

clipboard.png

下面以GET方式的queryString的解码过程来说解。首先咱们思考一下,如何才能获得原来的中文呢?固然是先把Hex数字使用UTF-8转码一次,获得浏览器初步处理的参数,如:title=JVM%20%E8%B0%83%E4%BC%98,而后再对原来非ASCII字符的部分使用UTF-8转码一次,获得最初值:title=JVM 调优。中文这一块我也没找到相关资料,我就分析一下英文的解码过程吧。

1.英文参数的状况

假设咱们原有的请求并不含中文参数,好比说:title=JVMoptimize 。那么在服务器端调用request.getParameter的方法时,会先进行转码,而charset由http请求的header中的contentType决定,不然使用ISO-8859-1。要想使用contentType的charset,还须要把<Connector URIEncoding="UTF-8" useBodyEncodingForURI="true" />设置为true,注意,true只是设置queryString的解码。到这里,对Hex的解码就会采用contentType的UTF-8进行解码了,咱们就能够还原获得title=JVMoptimize了,而后取到JVMoptimize这个参数值。

2.中文参数的状况

咱们再来说一讲中文参数的问题,由于在chrome中,非ASCII字符会采用UTF-8先进行一次编码;那么其实在服务器端,咱们能够本身思考一下。由于若是是纯英文的参数,下图是title=JVM optimize的请求,在初步处理时,空格是Hex的%20,也就是说纯英文下%后面必定是20,%20表明了一个空格。而若是是中文参数,由于浏览器手动在每个字节前加了%,注意,这样咱们服务器端经过%和其后面的是否跟着20就能够知道这里是空格仍是表明着中文参数了。

clipboard.png

queryString解码的猜测

咱们能够作出设想,在对queryString进行第一次转码以后,可能有2种基本状况:

  • 纯英文,还有空格的参数。原参数如:title=JVM optimize
    那么第一次转码,会获得:title=JVM%20optimize
  • 中文,还有空格的参数。原参数如:title=JVM 调优
    那么第一次转码。会获得:title=JVM%20%E8%B0%83%E4%BC%98

这个时候的结果就很明确了。我猜想,这时候服务器内部应该会对%进行检测,而后作出相应的处理。下面是个人猜想:

若是检测到%,那么看看其后面是否跟着20?是的话,就表示这是一个空格,将其转化(解码)为空格" " ;不是的话,表明这一块将是中文字符(或其余非ASCII字符,如日文,韩文),就把这一块连续的%剔除,再用UTF-8转码,就获得了中文字符。

上面应该是挺靠近真实状况的解释了,由于确定对非ASCII的解码要进行2次,上面的依据也挺充足的。

其余

那么我已经对url的编码解码过程作了一个分析,要注意的点和须要设置的地方在文中已经提到了。对于网上常见的一个设置:request.setCharacterEncoding(charset),设不设置都无所谓了,它的做用和contentType是同样的。

相关文章
相关标签/搜索