在开发中经常需要对用户输入的数据进行编码然后才能通过HTTP请求发送给后台,或者对传递过来的数据进行解码。在JS中原生提供了三种编码/解码方式,分别是 encodeURI、 encodeURIComponent和 escape。
为什么URL需要编码?
URI设计要求可移植,其中包括安全传输、方便阅读、完整性。
安全传输:不能在传递过程中有些信息被过滤掉
方便阅读:不能有空白字符
完整性:不能有的字符表示不了内容,例如中文
结合考虑URL使用ASCII字符集,而这个字符集是有限的,怎么表示无限的字符呢?并且ASCII中还有些被URL保留,例如#、&、?、/等。
这时候就需要编码,编码规则是使用使用%加上两个表示字符ASCII码的16进制数。
例如:
~ 对应 126 对应 0x7E 对应 %7E
空格 对应 32 对应 0x20 对应 %20
并且我们知道ASCII是用一个字节表示的一个可以表示256个字符,2的8次方,一个8bit。
但是汉字这显然是不够的,有的时候需要3个字节来表示所以encodeURIComponent('中')就变成了%E4%B8%AD
encodeURI
该方法不会对ASCII表中的字母和数字编码,同时也不会对ASCII中的标点符号编码 -_.~*’() 在URI中具有特殊含义的符号 **;/?😡&=+$,#**同样不会被编码。
var url = 'https://google.com/pathname?a=1&b=abcde&c=黄山#hash';
encodeURI(url); // 返回 https://google.com/pathname?a=1&b=abcde&c=%E9%BB%84%E5%B1%B1#hash
encodeURI("-_.~*'()"); // 返回 -_.~*'()
encodeURI(";/?:@&=+$,#"); // 返回 ;/?:@&=+$,#
encodeURIComponent
该方法相比encodeURI多编码URI中具有特殊含义的符号 ;/?😡&=+$,#
var url = 'https://google.com/pathname?a=1&b=abcde&c=黄山#hash';
encodeURIComponent(url); // 打印 "https%3A%2F%2Fgoogle.com%2Fpathname%3Fa%3D1%26b%3Dabcde%26c%3D%E9%BB%84%E5%B1%B1%23hash"
encodeURIComponent("-_.~*'()"); // 返回 -_.~*'()
encodeURIComponent(";/?:@&=+$,#"); // 返回 %3B%2F%3F%3A%40%26%3D%2B%24%2C%23
通过对比可看出方法encodeURI和encodeURIComponent编码中文的返回结果是一样的。
encodeURI("黄山"); // 返回 %E9%BB%84%E5%B1%B1
encodeURIComponent("黄山"); // 返回 %E9%BB%84%E5%B1%B1
escape(不推荐使用,推荐使用上面两个方法代替)
该方法会对ASCII中 *字母、数字及符号@-_+./**之外的所有字符进行编码。
var url = 'https://google.com/pathname?a=1&b=abcde&c=黄山#hash';
escape(url); // 返回 https%3A//google.com/pathname%3Fa%3D1%26b%3Dabcde%26c%3D%u9EC4%u5C71%23hash
console.log(escape("*@-_+./")); // 打印 *@-_+./
escape对于汉字的编码和上面两个方法的编码结果并不一样。
encodeURI("黄山"); // 返回 %E9%BB%84%E5%B1%B1
encodeURIComponent("黄山"); // 返回 %E9%BB%84%E5%B1%B1
escape("黄山"); // 返回 %u9EC4%u5C71
#解码
三种编码方法对应的解码方法分别是:
编码 解码
encodeURI decodeURI
encodeURIComponent decodeURIComponent
escape unescape
var res = encodeURI("黄山"); // %E9%BB%84%E5%B1%B1
decodeURI(res); // 返回 黄山
var res = encodeURIComponent("黄山"); // %E9%BB%84%E5%B1%B1
decodeURI(res); // 返回 黄山
var res = escape("黄山"); // %u9EC4%u5C71
unescape(res); // 返回 黄山