前言
- 当你在浏览器输入的URL包括中文或一些特殊符号时,查看网络请求,会发现被编码成了
%XX
的形式 - 当你使用
axios qs
构造请求时,也会发现对数据进行了百分百比编码。 - 另外你可能发现不同浏览器或package的编码方式也不尽相同
而这些不同的编码方式并不会影响服务器对数据的解析,比如{ 'a b+~': 'A B+~' }
,
qs
会编码成a%20b%2B~=A%20B%2B~
,而当axios
设置application/x-www-form-urlencoded
头时会编码成a+b%2B%7E=A+B%2B%7E
,使用co-body
的parse.form
都能正确解析为{ 'a b+~': 'A B+~' }
。下面就对浏览器的url编码、qs
、axios
、和application/x-www-form-urlencoded
做简单的解释。
为何需要编码?
我们都知道,HTTP
报文是面向ascii
的,对于中文肯定是需要编码的,另外URL又有一些特殊字符:/?
等,这些字符有特殊的功能,是否编码将影响URL的含义,称之为保留字符。另外又人为规定了一些字符字母数字~-._
等,这些字符是否编码都相等,称之为非保留字符。RFC2396做了如下规定:
- 保留字符:
";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
- 非保留字符:
字母 | 数字 | "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
不过参考意义有限,因为许多实现并不严格遵守 : (
URL和URLSearchParams
不同浏览的编码集不尽相同,以下以Chrome为例
当使用new URL('https://example.com/?a=哈哈')
构造URL时,会对参数进行解析形成如下对象,path、search、hash都进行了编码,并对search进一步解析形成URLSearchParams
其中不同部分的的编码集还不相同,
- path:会对除RFC3986的保留字符、非保留字符和
"%" | "[" | "]"
外进行编码。 - search:会对除
!$%&()*+,-.:;@[]^_{|}~/\
和` 外进行编码 - hash:会对除
!$%&()*+,-.:;@[]^_{|}~?/\='
外进行编码
我们不需要记住全部,因为我们主要关注点在search,而search只需要对常见的影响search解析的?=&#+
等字符进行编码就好,encodeURIComponent()
恰好可以满足大多数需求。
URLSearchParams的解析过程
URLSearchParams
内部使用x-www
的编解码规范
- 当以字符串进行初始化时,因为
new URL()
时,会有一部分字符没有被编码比如~
,所以额外添加了x-www
的解码这一步骤。- x-www的解码
- x-www的编码
- 将%20换为+
- 以对象初始化或set()时
- x-www的编码
- 将%20换为+
- get()时是使用的x-www解码后的字符串
x-www-form-urlencoded的解码
对除a-zA-Z0-9*-._
外其他所有字符进行,比如?a%200b+~=A%20B+~
- 以
&
切成数组[a%20b+~=A%20B+~]
- 将+换成空格
- 进行解码
[a b ~, A B ~]
x-www-form-urlencoded的编码
对除a-zA-Z0-9*-._
外其他所有字符进行,比如[a b+~, A B+~]
- 对
key value
进行编码[a%20b%2B%7E, A%20B%2B%7E]
- 形成
a%20b%2B%7E=A%20B%2B%7E
可以注意到,URLSearchParams
字符串和对象两种初始化总有哪些对不上的,它确实是对不上的:
所以谨慎使用URLSearchParams
的字符串初始化 : (
encodeURI()和encodeURIComponent()
和RFC2396类似
- 保留字符:
:/?#@$&+,;=
- 非保留字符:
!~'()
和*-._
和字母数字
encodeURI()
对除以上全部外进行编码,encodeURIComponent()
还会对保留字符编码成为居家必备好帮手 : )
以上就是浏览器相关,总结就是search中使用encodeURIComponent()
工具包
qs
axios
- url上的编码
- body指定x-www-form-urlencoede
工具包的编码更乱了,不过都对+
进行了编码,也不涉及页面对search的使用,只进行网络请求的发送,只要服务器按照x-www
的方式解码都没问题