关于url:转载阮一峰关于URL编码

6次阅读

共计 3409 个字符,预计需要花费 9 分钟才能阅读完成。

一、问题的由来

URL 就是网址,只有上网,就肯定会用到。

一般来说,URL 只能应用英文字母、阿拉伯数字和某些标点符号,不能应用其余文字和符号。比方,世界上有英文字母的网址 ”http://www.abc.com”,然而没有希腊字母的网址 ”http://www.aβγ.com”(读作阿尔法 - 贝塔 - 伽玛.com)。这是因为网络规范 RFC 1738 做了硬性规定:

“…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 unencoded within a URL.”
“ 只有字母和数字[0-9a-zA-Z]、一些特殊符号 ”$-_.+!*'(),”[不包含双引号]、以及某些保留字,才能够不通过编码间接用于 URL。”

这意味着,如果 URL 中有汉字,就必须编码后应用。然而麻烦的是,RFC 1738 没有规定具体的编码方法,而是交给应用程序(浏览器)本人决定。这导致 ”URL 编码 ” 成为了一个凌乱的畛域。

上面就让咱们看看,”URL 编码 ” 到底有多凌乱。我会顺次剖析四种不同的状况,在每一种状况中,浏览器的 URL 编码方法都不一样。把它们的差别解释分明之后,我再说如何用 Javascript 找到一个对立的编码方法。

二、状况 1:网址门路中蕴含汉字

关上 IE(我用的是 8.0 版),输出网址 http://zh.wikipedia.org/wiki/ 春节。留神, 春节 这两个字此时是网址门路的一部分。

查看 HTTP 申请的头信息,会发现 IE 理论查问的网址是http://zh.wikipedia.org/wiki/%E6%98%A5%E8%8A%82。也就是说,IE 主动将 ” 春节 ” 编码成了%E6%98%A5%E8%8A%82

咱们晓得,” 春 ” 和 ” 节 ” 的 utf- 8 编码别离是 E6 98 A5E8 8A 82,因而,%E6%98%A5%E8%8A%82就是依照程序,在每个字节前加上 % 而失去的。(具体的转码办法,请参考我写的《字符编码笔记》。)

在 Firefox 中测试,也失去了同样的后果。所以,论断 1 就是,网址门路的编码,用的是 utf- 8 编码。

三、状况 2:查问字符串蕴含汉字

在 IE 中输出网址http://www.baidu.com/s?wd= 春节。留神,” 春节 ” 这两个字此时属于查问字符串,不属于网址门路,不要与状况 1 混同。

查看 HTTP 申请的头信息,会发现 IE 将 春节 转化成了一个乱码。

切换到十六进制形式,能力分明地看到,” 春节 ” 被转成了B4 BA BD DA

咱们晓得, 的 GB2312 编码(我的操作系统 ”Windows XP” 中文版的默认编码)别离是 B4 BABD DA。因而,IE 实际上就是将查问字符串,以 GB2312 编码的格局发送进来。

Firefox 的解决办法,略有不同。它发送的 HTTP Head 是wd=%B4%BA%BD%DA。也就是说,同样采纳 GB2312 编码,然而在每个字节前加上了%

所以,论断 2 就是,查问字符串的编码,用的是操作系统的默认编码。

四、状况 3:Get 办法生成的 URL 蕴含汉字

后面说的是间接输出网址的状况,然而更常见的状况是,在已关上的网页上,间接用 Get 或 Post 办法收回 HTTP 申请。

依据台湾中兴大学吕瑞麟老师的试验,这时的编码方法由网页的编码决定,也就是由 HTML 源码中字符集的设定决定。

  <meta http-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 办法的编码,用的是网页的编码。

五、状况 4:Ajax 调用的 URL 蕴含汉字

后面三种状况都是由浏览器收回 HTTP 申请,最初一种状况则是由 Javascript 生成 HTTP 申请,也就是 Ajax 调用。还是依据吕瑞麟老师的文章,在这种状况下,IE 和 Firefox 的解决形式齐全不一样。

举例来说,有这样两行代码:

  url = url + "?q=" +document.myform.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 个(十六进制)字符。

它的具体规定是,除了 ASCII 字母、数字、标点符号 @ * _ + - . / 以外,对其余所有字符进行编码。在 \u0000\u00ff之间的符号被转成 %xx 的模式,其余符号被转成 %uxxxx 的模式。对应的解码函数是unescape()

所以,Hello Worldescape() 编码就是Hello%20World。因为空格的 Unicode 值是20(十六进制)。

还有两个中央须要留神。

首先,无论网页的原始编码是什么,一旦被 Javascript 编码,就都变为 unicode 字符。也就是说,Javascipt 函数的输出和输入,默认都是 Unicode 字符。这一点对上面两个函数也实用。

其次,escape()不对 + 编码。然而咱们晓得,网页在提交表单的时候,如果有空格,则会被转化为 + 字符。服务器解决数据的时候,会把 + 号解决成空格。所以,应用的时候要小心。

七、Javascript 函数:encodeURI()

encodeURI()是 Javascript 中真正用来对 URL 编码的函数。

它着眼于对整个 URL 进行编码,因而除了常见的符号以外,对其余一些在网址中有非凡含意的符号; / ? : @ & = + $ , #,也不进行编码。编码后,它输入符号的 utf- 8 模式,并且在每个字节前加上%

它对应的解码函数是decodeURI()


须要留神的是,它不对单引号 ’ 编码。

八、Javascript 函数:encodeURIComponent()

最初一个 Javascript 编码函数是 encodeURIComponent()。与encodeURI() 的区别是,它用于对 URL 的组成部分进行个别编码,而不用于对整个 URL 进行编码。

因而,; / ? : @ & = + $ , #,这些在 encodeURI() 中不被编码的符号,在 encodeURIComponent() 中通通会被编码。至于具体的编码方法,两者是一样。


它对应的解码函数是decodeURIComponent()

正文完
 0