# 为什么要进行URL编码
更详细的参考:为什么要进行URL编码 (opens new window)
Http协议中参数的传输是key=value键值对形式的,如果要传多个参数就需要用&符号对键值对进行分割。如?name1=value1&name2=value2,这样在服务端在收到这种字符串的时候,会用&分割出每一个参数,然后再用=来分割出参数值。
TIPS
- RFC3986文档规定,URL中只允许包含英文字母
a-zA-Z、数字0-9、-_.~4个特殊字符以及所有保留字符。 - RFC3986中指定了以下字符为保留字符:
!、*、'、(、)、;、:、@、&、=、+、$、,、/、?、#、[、]。 - 比较常见的其他禁止使用的包括百分号、引号、空格、尖括号(<>)等。
但是如果我的参数值中就包含=或&这种特殊字符的时候该怎么办?
比如说name1=value1,其中value1的值是va&lu=e1字符串,那么实际在传输过程中就会变成这样name1=va&lu=e1。
解决的办法就是对参数进行URL编码:
URL编码通常也被称为百分号编码(URL Encoding,also known as percent-encoding),只是简单的在特殊字符的各个字节前加上%
WARNING
这里并不会简单的像有些文章那样说的会智能的编码成name1=va%26lu%3De1,这个在浏览器地址栏里面都不会编码,就是变成了两个参数,传到后端接收的也是两个参数。解决办法就是自己手动去拼接URL,借助其他工具函数来手动把参数编码然后拼接起来,比如encodeURIComponent。
平时开发中也是这样,前端封装的请求就会去把参数编码然后再传给后端,如使用qs库。
# URL编码的规则是什么,为什么要用这个
- 网址路径的编码,用的是UTF-8编码。
- URL中查询字符串的编码,用的是操作系统的默认编码。
- GET和POST方法的编码,用的是网页的编码。
<meta http-equiv="Content-Type" content="text/html;charset=xxxx"> - 网页里的form编码不完全取决于网页编码,form标记中有一个
accept-charset属性,在非ie浏览器中,如果将其赋值(比如accept-charset="UTF-8"),则表单会按照这个值表示的编码方式进行提交。
对于非ASCII字符,需要使用ASCII字符集的超集进行编码得到相应的字节,然后对每个字节执行百分号编码。对于Unicode字符,RFC文档建议使用UTF-8对其进行编码得到相应的字节,然后对每个字节执行百分号编码。如中文使用UTF-8字符集得到的字节为0xE4 0xB8 0xAD 0xE6 0x96 0x87,经过URL编码之后得到%E4%B8%AD%E6%96%87。
如果某个字节对应着ASCII字符集中的某个非保留字符,则此字节无需使用百分号表示。
为什么用UTF-8?
参考:为什么要有UTF-8的疑问? (opens new window)
- UTF-8是Unicode编码的实现方式之一,在Unicode标准中,我们目前使用的是UCS-4,即字符集中每一个字符的字符代码都是用4个字节来表示,其中字符代码0~127兼容ASCII字符集,一般的通用汉字的字符代码也都集中在65535之前,使用大于65535的字符代码,即需要超过两个字节来表示的字符代码是比较少的。因此,如果仍然依旧采用字符代码和字符编码相一致的编码方式,那么拉丁字母原本仅需一个字节编码,目前就需要4个字节进行编码,汉字原本仅需两个字节进行编码,目前也需要4个字节进行编码,这对于存储或传输资源而言是很不划算的。因此就需要在字符代码和字符编码间进行再编码,这样就引出了UTF-8、UTF-16等编码方式。基于上述需求,UTF-8就是针对位于不同范围的字符代码转化成不同长度的字符编码,同时这种编码方式是以字节为单位,并且完全兼容ASCII编码,即0X00-0X7F的字符代码和字符编码完全一致,也是用一个字节来编码ASCII字符集,而常用汉字在Unicode中的字符代码是4E00-9FA5,在文末的对应关系中我们看到是用三个字节来进行汉字字符的编码(拉丁文:扩展B 0180-024F 以后的占4个字节)。UTF-16同理,就是以16位二进制数为基本单位对Unicode字符集中的字符代码进行再编码,原理和UTF-8一致。因此,我们可以看出,在目前全球互联的大背景下,Unicode字符集和编码方式解决了跨语言、跨平台的交流问题,同时UTF-8等编码方式又有效的节约了存储空间和传输带宽,因而受到了极大的推广应用。
- 根据UTF-8的编码规则,从UTF-8字节流任何一个地方截断都可以跳过非法的部分找到下一个字的开头,如果是unicode如果从一个字的中间截断会导致接下来所有的字符解析都是错的,这在不够可靠的网络传输中是有利的。
- 现有的unicode标准不是用2个字节而是3个字节(最大21位)。而UTF-8则是变长的,对于英文字符,一个字节就够了,而网络上传输的大部分为英文字符,所以UTF-8更节省存储空间和宽带。
Unicode字符代码与UTF-8编码的对应关系:
| Unicode字符代码 | UTF-8编码 |
|---|---|
| 0000 0000-0000 007F | 0xxxxxxx |
| 0000 0080-0000 07FF | 110xxxxx 10xxxxxx |
| 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
| 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
- 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。