URL 里经常能看到一堆 %E4%B8%AD 这样的百分号符号,这就是 URL 编码(也叫百分号编码)。它存在的原因很直接:URL 的语法本身对能出现哪些字符有严格限制,中文、空格、某些符号都不能直接塞进去。
URL 语法里,/、?、&、=、# 等符号都有结构性含义(分隔路径、开始查询参数、分隔参数、赋值、定位锚点),如果内容本身也包含这些符号,直接放进 URL 会造成解析歧义——服务器分不清这是"数据"还是"结构符号"。另外,URL 传统上只允许一部分 ASCII 字符,中文、日文等非 ASCII 字符以及空格都不被允许直接出现。解决方法就是把这些"有问题"的字符转换成安全的 %XX 形式。
规则很直接:把字符对应的字节,用两位十六进制数表示,前面加上 %。比如空格的 ASCII 码是 0x20,编码后就是 %20;中文字符要先按 UTF-8 转成字节,再逐字节编码——"中"字的 UTF-8 编码是三个字节 E4 B8 AD,所以编码结果是 %E4%B8%AD。这也是为什么中文字符编码后往往变成一长串 %XX%XX%XX——一个汉字通常占 UTF-8 的 3 个字节,编码后就是 3 组 %XX。
JavaScript 提供了两个编码函数,用途不同:
encodeURIComponent:编码范围最广,几乎所有特殊字符(包括 /、?、&、=)都会被编码——用于编码单个参数值,因为参数值本身不应该包含 URL 结构符号,如果参数值里恰好有 & 或 =,必须编码掉,否则会被误判成新的参数分隔符encodeURI:编码范围小得多,会保留 /、?、&、=、# 这些 URL 结构字符不编码——用于编码整条 URL,因为这些符号在整条 URL 里是有意义的结构,不应该被编码掉一个常见的坑:如果用 encodeURI 去编码一个参数值(而不是整条 URL),参数值里的 & 和 = 不会被编码,一旦参数值本身包含这些符号,就会破坏 URL 的参数结构——所以编码单个参数值时应该用 encodeURIComponent,编码整条 URL 时才用 encodeURI。
HTML 表单提交(Content-Type: application/x-www-form-urlencoded)用的编码规则和标准 URL 百分号编码略有差异:空格被编码成 + 号,而不是 %20。这是历史遗留问题——早期 HTML 表单规范就是这么定义的,一直沿用至今。这也是为什么处理表单数据时,如果直接按标准 URL 解码规则去解析(把 + 当作字面的加号而不是空格),会得到错误的结果——必须先把 + 换成空格,再做百分号解码。
在线工具:URL编码解码 · Escape编码解码