我们在浏览网页的时候,在浏览器的地址栏偶尔会看到地址中带有很多的百分号,这是因为浏览器对URL进行了编码。

 

URL编码又称为百分号编码,编码方式很简单,就是把单个字节用16进制表示,然后在其前面放置一个百分号。 比如有"abc"这样一个串,我们把他转换成ascii的字节序后,用16进制表示成这样: 616263,把他进行百分号编码就是在各个字节前加上“%”,结果如下: 61%62%63 

 

在URL中,并不是所有的字符都需要编码。正常的字符不需要编码,比如说字母数字,而一些特殊的字符比如说字符中含有&等符号,就需要编码。举个例子,比如说一个键值对中含有&符号,name1=va&lu=e1,va&lu=e1是一个整体,是name1的值,那么如果只是这样传给服务器,&最为分隔符,服务器会理解为有2个键值对,所以需要转码。而且有一点,浏览器在地址栏中显示的时候就已经给转码了,因为这样用户看到的时候,也不会误解有2个键值对了。

 

我们都知道Http协议中参数的传输是"key=value"这种简直对形式的,如果要传多个参数就需要用“&”符号对键值对进行分割。如"?name1=value1&name2=value2",这样在服务端在收到这种字符串的时候,会用“&”分割出每一个参数,然后再用“=”来分割出参数值。 

 

针对“name1=value1&name2=value2”我们来说一下客户端到服务端的概念上解析过程: 上述字符串在计算机中用ASCII吗表示为: 

6E616D6531 3D 76616C756531 26 6E616D6532 3D76616C756532。 
6E616D6531:name1 
3D:= 
76616C756531:value1 
26:& 
6E616D6532:name2 
3D:= 
76616C756532:value2

服务端在接收到该数据后就可以遍历该字节流,首先一个字节一个字节的吃,当吃到3D这字节后,服务端就知道前面吃得字节表示一个key,再想后吃,如果遇到26,说明从刚才吃的3D到26子节之间的是上一个key的value,以此类推就可以解析出客户端传过来的参数。 

 

现在有这样一个问题,如果我的参数值中就包含=或&这种特殊字符的时候该怎么办。比如说“name1=value1”,其中value1的值是“va&lu=e1”字符串,那么实际在传输过程中就会变成这样“name1=va&lu=e1”。我们的本意是就只有一个键值对,但是服务端会解析成两个键值对,这样就产生了奇异。 

 

如何解决上述问题带来的歧义呢?解决的办法就是对参数进行URL编码 

URL编码只是简单的在特殊字符的各个字节前加上%,例如,我们对上述会产生奇异的字符进行URL编码后结果:“name1=va%26lu%3D”,这样服务端会把紧跟在“%”后的字节当成普通的字节,就是不会把它当成各个参数或键值对的分隔符。 

 

另外一个问题,就是为什么我们要用ASCII传输,可不可以用别的编码?当然可以用别的编码,你自己可以开发一套编码,然后自己解析。就像大部分国家都有自己的语言一样。那国家之间要交流,怎么办?  用英语把,英语的使用范围最广。

 

(这里我一直有一个疑问,就是Http请求这些内容是按照什么规则转为二进制数据包然后通过TCP传输的呢?是算出每一个字母的ASCII码值,然后转换成对应的二进制数字进行传输吗?好吧,姑且不管这个问题,但是有一点可以肯定,就是URL是转成16进制然后发送到网络,最后服务器接收到TCP的数据报文后,也是能够从二进制的数据中还原出来这个16进制的URL的。或许是HTTP协议在建立TCP数据包的时候,会告诉下一层,我这是ASCII码的东西,还是已经转换完毕的二进制的东西)