混乱的百分比编码

172 阅读2分钟

前言

  • 当你在浏览器输入的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-bodyparse.form都能正确解析为{ 'a b+~': 'A B+~' }。下面就对浏览器的url编码、qsaxios、和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

image.png

其中不同部分的的编码集还不相同,

  • 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字符串和对象两种初始化总有哪些对不上的,它确实是对不上的:

image.png

image.png

所以谨慎使用URLSearchParams的字符串初始化 : (

encodeURI()和encodeURIComponent()

和RFC2396类似

  • 保留字符::/?#@$&+,;=
  • 非保留字符:!~'()*-._字母数字

encodeURI()对除以上全部外进行编码,encodeURIComponent()还会对保留字符编码成为居家必备好帮手 : )

以上就是浏览器相关,总结就是search中使用encodeURIComponent()

工具包

qs

image.png

axios

  • url上的编码

image.png

  • body指定x-www-form-urlencoede

image.png

工具包的编码更乱了,不过都对+进行了编码,也不涉及页面对search的使用,只进行网络请求的发送,只要服务器按照x-www的方式解码都没问题