这个实验,是在采用ssm框架的基础上演示的。
在前端向后端发出http请求时,有时候当咱们采用GET方式时,参数会被编码在url后面。那么这个url是如何编码解码的呢?前端
下面在chrome浏览器和postman下模拟请求,用fiddler来监控请求发出信息。chrome
chrome游览器地址输入: json
这个路径是手动输入的,黑色线是url,黄色线是uri,绿色线是queryString。这时F12,而后咱们路径按下回车。后端
chrome地址:数组
chrome监控: 浏览器
fiddler监控:tomcat
咱们关注chrome控制台和fiddler的状况,能够发现,chrome发出这个http请求的时候,对查询参数进行了编码。咱们在网站(https://www.bejson.com/conver... 进行Hex转字符的操做,能够发现:中文字符被编码成16进制数,并且每一个字节(byte)的16进制数前都被浏览器加上了一个%。(下图中,20E8B083这4个字节对应“调”,E4BC98这3个字节对应“优”)服务器
浏览器编码url的风格: 到这里,可能你有点迷惑了。我来解释一下,根据URL的编码规范,浏览器会把URL中的非ASCII字符按照某种编码格式(chrome是utf-8)编码成byte数组后,转成16进制数字,而后在每一个16进制数字前加上%分隔。网络
到如今,应该清楚了浏览器GET传参时的编码过程了。值得一提的是,在实践中,咱们最糟糕也只会在GET方式的url后面携带中文参数,在servletPath(也就是?前的一段)中咱们不会去用中文的,除非你自找麻烦。框架
具体的传输: 其实,咱们尚未讲到url的传输。咱们要知道,在网络世界的传输中,全部的信息都是以字节传输的(byte[]),一个http请求的全部内容都是编码成byte数组后传输的,也就是0101这样的数字。为了方便显示,fiddler中用Hex来表示。能够这么理解,上面那个url路径只是一个初步处理后的string而已,咱们从fiddler中查看,
咱们对Hex进行几回copy查看:
能够看出,传输过程当中的Hex数组,就是咱们以前监控到的真正的http请求url通过了中文utf-8编码后的路径。
答案是确定的,手动设置一下确定是很是好的。
下面咱们以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
。
上面,咱们知道了uri/url这一块的内容解码过程。下面,咱们来看看queryString这部分的解码过程。
咱们在chrome中,F12查看http请求的详细信息,能够发现查询参数被做为parameters保存了下来。这里,能够告诉你们,经过GET方式发出http请求所携带的queryString以及经过POST方式发出http请求所携带的表单参数,也就是GET、POST这2种方式携带的参数,都会被做为parameters保存;在服务器端经过request.getParameter()方法能够获取到值。
下面以GET方式的queryString的解码过程来说解。首先咱们思考一下,如何才能获得原来的中文呢?固然是先把Hex数字使用UTF-8转码一次,获得浏览器初步处理的参数,如:title=JVM%20%E8%B0%83%E4%BC%98
,而后再对原来非ASCII字符的部分使用UTF-8转码一次,获得最初值:title=JVM 调优
。中文这一块我也没找到相关资料,我就分析一下英文的解码过程吧。
假设咱们原有的请求并不含中文参数,好比说: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
这个参数值。
咱们再来说一讲中文参数的问题,由于在chrome中,非ASCII字符会采用UTF-8先进行一次编码;那么其实在服务器端,咱们能够本身思考一下。由于若是是纯英文的参数,下图是title=JVM optimize
的请求,在初步处理时,空格是Hex的%20,也就是说纯英文下%后面必定是20,%20表明了一个空格。而若是是中文参数,由于浏览器手动在每个字节前加了%,注意,这样咱们服务器端经过%和其后面的是否跟着20就能够知道这里是空格仍是表明着中文参数了。
咱们能够作出设想,在对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是同样的。