《前端编码系列》
一、什么是URI
组件的概念
URI components,指URI的各个组成部分,包括:scheme、authority、path、query、fragment
https://user:password@example.com:8080/path/to/resource?query=string#fragment
保留字符
用途:提供一组可与URI中的其他数据区分开的分隔字符
范围:
| gen-delims | : | / | ? | # | [ | ] | @ | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| sub-delims | ! | $ | & | ' | ( | ) | * | + | , | ; | = |
- gen-delims,用于区分 URI 组件(scheme、authority、path、query、fragment)的分隔符
- sub-delims,用于区分 URI组件的子组件的分隔符
非保留字符
范围:保留字符外的其它字符,包括但不限于a-zA-Z、0-9、-、.、_、~ (波浪号)、所有非 ASCII 字符(对于非ASCII字符(如中文字符),虽然它们属于非保留字符,但在URI中直接使用可能会导致兼容性问题,所以在百分比编码中,把这些字符也进行了编码)
百分号编码
Percent-Encoding
用途:用于在URI的组件中表示非 ASCII 字符或保留字符,目的是确保URI中的字符不会与URI的语法结构冲突,也不会被错误地解释;同时使得URI可以包含广泛的字符集
实现方式:通过将一个8位字节(octet,指代具有8个bit的实体)转换为一个百分号%后跟两位的十六进制数来实现。
pct-encoded = % hexdig hexdig
| 字符 | 十六进制 | 百分比编码 |
|---|---|---|
| & | 26 | %26 |
| = | 3D | %3D |
| ? | 3F | %3F |
注意:存在2种百分号编码的字符 —— 空格
根据上下文,空白符 ' ' 将会转换为 '+' (如使用百分号编码的 application/x-www-form-urlencoded 消息),或者将会转换为 '%20'(如 URL 中)。
URI和URL
- URI:Uniform Resource Identifier,统一资源标识符,是一种用于标识某一互联网资源的字符串。主要用来标识,但不一定能定位。
- URL:Uniform Resource Locator,统一资源定位符,是 URI 的一个子集,专门用于标识和定位互联网上的资源。URL 提供了资源的位置信息,主要用来定位。
二、URI编码
什么是URI编码
URI(Uniform Resource Identifier,统一资源标识符)编码是指:将URI中的特殊字符转换成特定格式的过程。
为什么要编码
- 兼容URI组件中的非 ASCII 字符。URI 只允许包含 ASCII 字符集中的字符,非 ASCII 字符都需要通过「Percent-Encoding 百分比编码」方法进行编码。这是 URI规范定义 RFC3986 的规定,推测这么规定的目的是为了让URI在不同地区之间通用。
- 兼容URI组件中的保留字符。如果要在URI的组件内部包含这些字符,需要进行编码,否则可能会导致 URI 解析错误,如将组件中的特殊字符识别为分割符,导致内容被提前分割、解析错误。
- 兼容URI组件中的空格和其它控制字符。空格和一些特殊字符(eg:换行符)在URI中是不被允许的,如果要传递这些,就需要进行编码
escape(废弃)
生成新的由十六进制转义序列替换的字符串
console.log(escape("中文")); //输出:%u4E2D%u6587。ps:“中”的unicode编码值为U+4E2D,“文”的unicode编码值为U+6587
encodeURI
需要创建合法安全完成的URL时,使用该方法。
通过将特定字符替换成代表字符的UTF-8编码的一个、两个、三个或四个转义序列来编码,转义序列的个数取决于UTF-8编码字节数
【编码方式】:百分号编码
| UTF-8 | encodeURI(string) | |
|---|---|---|
| ``(空格) | \x20 | %20 |
é | \xC3\xA9 | %C3%A9 |
中 | \xE4\xB8\xAD | %E4%B8%AD |
𠜎 | \xF0\xA0\x83\xA7 | %F0%A0%83%A7 |
【不编码范围】 :保留的并且在 URI 中有特殊意思的字符
| 类型 | 包含 |
|---|---|
| 保留字符 | ; , / ? : @ & = + $ |
| 非转义的字符 | 字母 数字 - _ . ! ~ * ' ( ) |
| 数字符号 | # |
【特点】:主要目的是兼容非ASCII字符和一些特殊符号,能够保留URI原始的分隔符不被编码转义
【主要的适用场景】:创建合法、安全的完整URL,URL中并不能直接兼容非 ASCII 字符、以及空格、引号、尖括号等,使用 encodeURI() 可以确保这些字符被正确编码,从而创建出合法的URL。一些场景下需要将用户输入拼接到URL中,使用encodeURI()可以规避危险字符,以及处理前面提到的非法字符的问题。
该方法是幂等调用的吗?答:不是(见下面🌰),因为作为百分号编码起始前缀的 % 会被编码为 %25
console.log(encodeURI("中文")); //输出:%E4%B8%AD%E6%96%87
console.log(encodeURI(encodeURI("中文"))); //输出:%25E4%25B8%25AD%25E6%2596%2587
console.log(decodeURI("%E4%B8%AD%E6%96%87")); //输出:中文
console.log(decodeURI("%25E4%25B8%25AD%25E6%2596%2587")); //输出:%E4%B8%AD%E6%96%87
encodeURIComponent
该方法常用于编码URI组件的值,如query子组件(query参数)的值。
通过将特定字符替换成代表字符的UTF-8编码的一个、两个、三个或四个转义序列来编码。与 encodeURI 的区别仅在于编码范围更大
【编码方式】:百分号编码
【不编码的范围】 :
| 类型 | 包含 |
|---|---|
| 非转义的字符 | 字母 数字 - _ . ! ~ * ' ( ) |
console.log(encodeURIComponent("aB1-._~!*()'")); //输出:aB1-._~!*()'
【主要的适用场景】:创建无歧义的URL组件,在URL组件(如query参数)中包含特殊字符(如&)时,需要对特殊字符进行编码,否则会导致URL解析偏离预期。
三、URI解码
decodeURI
顾名思义,解码由encodeURI 创建字符串
decodeURIComponent
顾名思义,用于解码由 encodeURIComponent 方法创建的字符串