URL编码“陷阱”
作者:LuLi 来源:SimpleLife 时间:2008-03-04 16:57:00
上次谈到客户端和服务端的编码“陷阱”,其中对url编码只是提及带过,并没有做深入讨论,事实上由于浏览器环境的复杂和不一致性,我们也很容易掉进url编码“陷阱”。首先看一个demo,我的测试是在FF和IE6上进行的。
在FF下表现正常,而在IE6下当点击第一个链接的时候,服务端给我们返回的id变量值竟然出现了怪异,和我们传递过去的“实验室”不一致,这看起来似乎很怪异。整个过程中我对get过来的参数id除了做输出,没有做任何额外处理,上面的怪异现象实际上是浏览器造成的。
一、URL编码需要指定被编码字符的字符集
首先我们要明确的是在对ASCII码以外的字符做URL编码时,你要清楚的知道被编码的字符的字符集,这点很重要。例如我们要对“汉字”这两个字符做URL编码,你可能得到的是“%E6%B1%89%E5%AD%97”,也可能是“%BA%BA%D7%D6”。为何会有两个了?事实上还有更多。前者是UTF8下“汉字”的URL编码,后者是GB2312下“汉字”的URL编码。如果客户端是针对字符集A做的URL编码,而服务端默认是以字符集B处理,那显然就掉进陷阱了。(PS:随后有一个测试可以看到)
1、页面中的字符编码
当服务端将页面代码发送给客户端并显示在浏览器里时,该页面中的字符编码就已经确定了,它可能是服务端在header中直接指定的,也可能是在页面的meta信息中设置了charset,具体见客户端和服务端的编码“陷阱”中的第一和第二点分析。以上面那个怪异的demo为例,页面的字符集是utf-8,当点击第一个“实验室”链接时,IE6地址栏是“http://www.v-sky.com/demo/urlencode.php?id=实验室”,而FF下是“http://www.v-sky.com/demo/urlencode.php?id=%E5%AE%9E%E9%AA%8C%E5%AE%A4”,对比可知,对于链接中的非ASCII码IE是“不会”做处理的(PS:事实上IE的编码过程是在背后进行的,没有在地址栏展现给浏览者而已),而FF会根据字符本身的字符集做URL编码(PS:你可以将此页面字符集设置为GB2312以后测试,FF下的地址栏会变成GB2312对应的URL编码)
2、URL地址栏中的字符编码
同样在针对上面的怪异demo,刚才我们都是通过点击链接请求一个新的URL来传递参数,现在我们直接在地址栏中给id输入参数“实验室”,然后回车察看结果。你会发现无论是IE还是FF,服务端输出的变量都是乱码,在FF的地址栏中我们可以看到这里是针对GB2312字符集的“实验室”做的URL编码,而服务端是以UTF8编码处理的,这就造成了输出乱码,前面提到的陷阱出现了。
简单来说就是浏览器中输入字符的编码是根据浏览器和用户在浏览器上的个人设置来确定的,这里有一个详细的说明,我没有对各种情况都做测试,因为首先我不会用非ASCII码命名文件,其次非ASCII码的传参随后有更好的解决方案。
二、对ASCII码以外的特殊字符统一编码
实际项目中很少会出现包含非ASCII码的链接,能够避免这种情况最好,尤其是希望用户容易访问的地址更应当考虑易用性。但如果你真的因为某些原因无法避免,那么你只有主动对这些特殊URL进行统一的URL编码,避免IE这样的浏览器来捣乱,就跟demo中的第二个链接的做法一样。
对于接受用户输入而构造出来的URL请求,例如搜索引擎入口,至少会GET传递一个关键字参数。如果对你的项目而言这是一个很重要的功能,那么你可能需要将各种情况都考虑进来,这个功能www.google.cn考虑的就很不错,页面编码本身是utf-8的,如果从搜索框搜索的,那么URL中是针对UTF8的关键字做的URL编码,如果是用户从地址栏输入,也就是针对GB2312的字符集做的URL编码,这里google在服务端应该是做了字符编码的判断,同样能够准确得到搜索结果,可用性不错,嘿嘿。
(PS:这里我自己也有一个疑问,目前没有找到直接的资料说明。对于包含非ASCII码的链接,IE会在背后做编码处理,只是没有像FF那样直接在地址栏反应出来,这点在HTTP通信中有资料说明。针对上面的demo,我尝试将“实验室”更换为其他字符测试,例如“你好”、“奥运”等,IE下并为出现demo中的怪异情况,这就说明PHP在接收GET过来的参数时,对于ASCII码以外的某些特殊字符并没有正确接收,问题是出在哪儿了?如果哪位知道原因希望告知。)