JavaWeb开发编码系列(三)——URL规范
⽂章来⾃百度⽂库:(百度,wiki百科的地址不让有, csdn)
为了贴过来,在url后⾯加了“()”混淆⼀下,再次鄙视csdn。
因为地址blog系统不让粘贴,只能拷过来了,哎(⊙o⊙)…
⼀、问题的由来
URL就是⽹址,只要上⽹,就⼀定会⽤到。
"...Only alphanumerics [0-9a-zA-Z],the special characters "$-_.+!*'()," [not including the quotes - ed],and reserved characters used for their reserved purposes may be used unencodedwithin a URL."
“只有字母和数字[0-9a-zA-Z]、⼀些特殊符号“$-_.+!*'(),”[不包括双引号]、以及某些保留字,才可以不经过编码直接⽤于URL。”
这意味着,如果URL中有汉字,就必须编码后使⽤。但是⿇烦的是,RFC 1738没有规定具体的编码⽅法,⽽是交给应⽤程序(浏览器)⾃⼰决定。这导致“URL编码”成为了⼀个混乱的领域。
下⾯就让我们看看,“URL编码”到底有多混乱。我会依次分析四种不同的情况,在每⼀种情况中,浏览器的URL编码⽅法都不⼀样。把它们的差异解释清楚之后,我再说如何⽤Javascript到⼀个统⼀的编码⽅法。
⼆、情况1:⽹址路径中包含汉字
我们知道,“春”和“节”的utf-8编码分别是“E6 98 A5”和“E8 8A 82”,因此,“%E6%98%A5%E8%8A%82”就是按照顺序,在每个字节前加上%⽽得到的。(具体的转码⽅法,请参考我写的。)
在Firefox中测试,也得到了同样的结果。所以,结论1就是,⽹址路径的编码,⽤的是utf-8编码。
三、情况2:查询字符串包含汉字
查看HTTP请求的头信息,会发现IE将“春节”转化成了⼀个乱码。
切换到⼗六进制⽅式,才能清楚地看到,“春节”被转成了“B4 BA BD DA”。
我们知道,“春”和“节”的GB2312编码(我的操作系统“Windows XP”中⽂版的默认编码)分别是“B4 BA”和“BD DA”。因此,IE实际上就是将查询字符串,以GB2312编码的格式发送出去。
Firefox的处理⽅法,略有不同。它发送的HTTP Head是“wd=%B4%BA%BD%DA”。也就是说,同样采⽤GB2312编码,但是在每个字节前加上了%。
所以,结论2就是,查询字符串的编码,⽤的是操作系统的默认编码。
四、情况3:Get⽅法⽣成的URL包含汉字
前⾯说的是直接输⼊⽹址的情况,但是更常见的情况是,在已打开的⽹页上,直接⽤Get或Post⽅法发出HTTP请求。
根据台湾中兴⼤学,这时的编码⽅法由⽹页的编码决定,也就是由HTML源码中字符集的设定决定。
  <metahttp-equiv="Content-Type" content="text/html;charset=xxxx">
如果上⾯这⼀⾏最后的charset是UTF-8,则URL就以UTF-8编码;如果是GB2312,URL就以GB2312编码。
举例来说,百度是GB2312编码,Google是UTF-8编码。因此,从它们的搜索框中搜索同⼀个词“春节”,⽣成的查询字符串是不⼀样的。
百度⽣成的是%B4%BA%BD%DA,这是GB2312编码。
Google⽣成的是%E6%98%A5%E8%8A%82,这是UTF-8编码。
所以,结论3就是,GET和POST⽅法的编码,⽤的是⽹页的编码。
url编码处理五、情况4:Ajax调⽤的URL包含汉字
前⾯三种情况都是由浏览器发出HTTP请求,最后⼀种情况则是由Javascript⽣成HTTP请求,也就是Ajax调⽤。还是根据吕瑞麟⽼师的⽂章,在这种情况下,IE和Firefox的处理⽅式完全不⼀样。
举例来说,有这样两⾏代码:
  url = url +"?q=" +form.elements[0].value; //假定⽤户在表单中提交的值是“春节”这两个字
  http_request.open('GET',url, true);
那么,⽆论⽹页使⽤什么字符集,IE传送给服务器的总是“q=%B4%BA%BD%DA”,⽽Firefox传送给服务器的总
是“q=%E6%98%A5%E8%8A%82”。也就是说,在Ajax调⽤中,IE总是采⽤GB2312编码(操作系统的默认编码),⽽Firefox总是采⽤utf-8编码。这就是我们的结论4。
六、Javascript函数:escape()
好了,到此为⽌,四种情况都说完了。
假定前⾯你都看懂了,那么此时你应该会感到很头痛。因为,实在太混乱了。不同的操作系统、不同的浏览器、不同的⽹页字符集,将导致完全不同的编码结果。如果程序员要把每⼀种结果都考虑进去,是不是太恐怖了?有没有办法,能够保证客户端只⽤⼀种编码⽅法向服务器发出请求?
回答是有的,就是使⽤Javascript先对URL编码,然后再向服务器提交,不要给浏览器插⼿的机会。因为Javascript的输出总是⼀致的,所以就保证了服务器得到的数据是格式统⼀的。
Javascript语⾔⽤于编码的函数,⼀共有三个,最古⽼的⼀个就是escape()。虽然这个函数现在已经不提倡使⽤了,但是由于历史原因,很多地⽅还在使⽤它,所以有必要先从它讲起。
实际上,escape()不能直接⽤于URL编码,它的真正作⽤是返回⼀个字符的Unicode编码值。⽐如“春节”的返回结果
是%u6625%u8282,也就是说在Unicode字符集中,“春”是第6625个(⼗六进制)字符,“节”是第8282个(⼗六进制)字符。>>> javascript:escape("春节");
"%u6625%u8282"
它的具体规则是,除了ASCII字母、数字、标点符号“@ * _ + - . /”以外,对其他所有字符进⾏编码。在\u0000到\u00ff之间的符号被转成%xx的形式,其余符号被转成%uxxxx的形式。对应的解码函数是unescape()。
所以,“Hello World”的escape()编码就是“Hello%20World”。因为空格的Unicode值是20(⼗六进制)。
>>>javascript:escape("hello world");
"hello%20world"
还有两个地⽅需要注意。
⾸先,⽆论⽹页的原始编码是什么,⼀旦被Javascript编码,就都变为unicode字符。也就是说,Javascipt函数的输⼊和输出,默认都是Unicode字符。这⼀点对下⾯两个函数也适⽤。
>>>escape("\u6625\u8282");
"%u6625%u8282"
>>>unescape("%u6625%u8282");
"春节"
>>>unescape("\u6625\u8282");
"春节"
其次,escape()不对“+”编码。但是我们知道,⽹页在提交表单的时候,如果有空格,则会被转化为+字符。服务器处理数据的时候,会把+号处理成空格。所以,使⽤的时候要⼩⼼。
七、Javascript函数:encodeURI()
encodeURI()是Javascript中真正⽤来对URL编码的函数。
它着眼于对整个URL进⾏编码,因此除了常见的符号以外,对其他⼀些在⽹址中有特殊含义的符号“; / ? : @ & = + $ , #”,也不进⾏编码。编码后,它输出符号的utf-8形式,并且在每个字节前加上%。
>>>encodeURI("www.i?arg1=1&arg2=hello world");
"www.i?arg1=1&arg2=hello%20world"
>>> encodeURI("春节");
"%E6%98%A5%E8%8A%82"
它对应的解码函数是decodeURI()。
需要注意的是,它不对单引号'编码。
⼋、Javascript函数:encodeURIComponent()
最后⼀个Javascript编码函数是encodeURIComponent()。与encodeURI()的区别是,它⽤于对URL的组成部分进⾏个别编码,⽽不⽤于对整个URL进⾏编码。
因此,“; / ? : @ & = + $, #”,这些在encodeURI()中不被编码的符号,在encodeURIComponent()中统统会被编码。⾄于具体的编码⽅法,两者是⼀样。
它对应的解码函数是decodeURIComponent()。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。