Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1661736
  • 博文数量: 695
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4027
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-20 21:22
文章分类

全部博文(695)

文章存档

2018年(18)

2017年(74)

2016年(170)

2015年(102)

2014年(276)

2013年(55)

分类: Html/Css

2015-11-11 22:25:49

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

针对“name1=value1&name2=value2”我们来说一下客户端到服务端的概念上解析过程: 
  上述字符串在计算机中用ASCII吗表示为: 
  6E616D6531 3D 76616C756531 26 6E616D6532 3D 76616C756532。 
   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传输,可不可以用别的编码? 
    当然可以用别的编码,你自己可以开发一套编码,然后自己解析。就像大部分国家都有自己的语言一样。那国家之间要交流,怎么办?  用英语把,英语的使用范围最广。

***********************番外篇(URL编码)************************ 

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

在URL的表示中并非所有的字符都需要进行百分号编码,RFC3986(URI规范)中规定保留字符和非保留字符可以不用编码,其它字符必须用百分号编码。 
RFC1738(URL规范)规定保留和非保留字符可以直接用于URL中。 

保留字符: 
       ! * ' ( ) ; : @ & = + $ , / ? # [ ] 
非保留字符: 
       a-z A-Z 0-9 - _ . ~ 

在一个URL中,如果一个保留字符在特定上下文中有特殊含义,而这个保留字在URL中又有特殊目的,那么该字符必须百分号编码。 
比如"/",在URL中表示路径分隔符,如果某个路径包含该字符,那么在路径内的该字符就必须进行百分号编码,否则就会和真正的路径分隔符产生歧义. 

还有一种需要进行百分号编码的就是”其它字符“,所谓的其它字符就是在保留字符和非保留字符之外的字符,比如ascii码的非显示字符、汉字字符等。 

通过前面我们知道,对一个字符进行百分号编码前需要得到该字符的字节流形式,也就是说我们需要根据某种字符编码,将该字符转换成字节流,应该用哪种字符编码(比如GBK、UTF-8等)在RFC1738中并没有给出,所以各个程序(比如浏览器)有自的方式,但是在2005年1月RFC3986做出了强制规定,强制"其它字符"要先转换为UTF-8字节序列,然后对其字节值进行百分号编码。 

对"a中"这个字符串对其百分号编码的过程大概如下: 
   1)将串转换成utf-8编码形式的字节流,那么就是0x61 E4 B8 AD 
   2)顺序取一个字节,是非保留字? 
   3)是,则该字节不用编码,直接输出该字节表示的ascii字符 
   4)不是,则证明该字节需要编码,先输出"%"再输出该字节的16进制大写形式 
   5)如果还有下一个字节则执行步骤 3),如此循环直到编码完成 
   6)最后结果 "a%E4%B8%AD" 

对"a%E4%B8%AD"串的解码过程如下: 
   1)将字符串转变为字节流 
   2)顺序取一个字节,标记字节位置为i,比较该字节是否是'%' 
   3)不是,直接输出 
   4)是,取(i+1)位置字节左移4位 + (i+2)位置字节&0xF ,然后输出 
   5)跳过两个字节,如果还有下一字节则执行步骤 3), 如此循环完成解码 

好,有了上面的知识后我们在看一下浏览器对URL的编码是不是跟规范一样。 
首先说下URL的组成: 
   {[/app/中国]} ? (name=val中) 
   {}:代表URL (绝对URI) 
   []:代表URI (相对URI,这种标示符依赖具体的环境) 
   ():代表Query String 

直接地址栏中输入,对URI则在IE8、chrome、firefox浏览器上发现都是用UTF-8进行百分号编码的. 
但是对query string,IE8用的是未经过百分号编码的GBK原码(可能用的操作系统的编码);chrome、firefox上用的是utf-8进行百分号编码。 

在网页中嵌套的URL,对于URL的路径部分,IE8、chrom、firefox用的是UTF-8编码进行百分号编码。 
对于query string部分,这三种浏览器采用的是http响应头头中的 
  Content-Type:text/html; charset=gbk 指定; 
如果未指定则用页面中的 
  指定。 

通过以上我们可以知道,各个浏览器对于URL的路径部分使用的编码方式和规范一致,但是对于Query string部分稍有差别. 

另外说下javascript的encodeURI()方法,该方法对保留字符不进行编码,比如以下字符不进行编码: 
  a-z A-Z 0-9  - _ . ! ~ * ' ( ) ; / ? : @ & = + $ , # 
所以如果某个URL的数据部分包含特殊的保留字符,用该方法编码该数据后可能无法区分该字符是数据的一部分还是URL的一部分(比如路径分隔符). 

所以javascript就有了encodeURIComponent()方法,从名字上就可以看到该方法对URL的"成份"进行编码,用它编码后可以明确区分某个字符是"成份"还是URL的特殊分隔符。 
该方法不对非保留字符编码,如: 
   a-z A-Z 0-9 - _ . ~ 
其他字符都做编码。
阅读(889) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~