一个典型的坏链接
你拼了一个搜索链接,英文下一切正常,用户一输入中文就崩:
https://example.com/search?q=书签管理 & page=2
服务器收到的 q 是 书签管理 ,还多了一个叫 page 的参数——本该属于查询值的 & 被当成了分隔符。#、=、?、+ 和空格也有同样的问题。
解决办法是百分号编码(URL 编码):把不安全字符替换成 % 加两个十六进制数字,表示它的 UTF-8 字节。
书签管理 → %E4%B9%A6%E7%AD%BE%E7%AE%A1%E7%90%86
& → %26
空格 → %20
哪些字符是安全的
RFC 3986 把字符分成"未保留"和"保留"两类,只有未保留字符可以原样出现:
| 类别 | 字符 | 说明 |
|---|---|---|
| 未保留 | A–Z a–z 0–9 - _ . ~ |
任何位置都安全 |
| 保留(结构类) | : / ? # [ ] @ |
在 URL 中有结构含义 |
| 保留(子分隔符) | ! $ & ' ( ) * + , ; = |
在查询串中有含义 |
| 其他 | 空格、"、<、>、%、{}、中文… |
必须编码 |
保留字符不是"不能用",而是"有含义"。关键问题永远是:这个 & 是想表达结构,还是想表达数据?如果是数据,就编码它。
encodeURI 和 encodeURIComponent 的区别
JavaScript 自带两个编码函数,行为完全不同:
const raw = 'https://example.com/search?q=书签 & page=2'
encodeURI(raw)
// https://example.com/search?q=%E4%B9%A6%E7%AD%BE%20&%20page=2
// 保留 : / ? & = —— 用来编码「一整个 URL」
encodeURIComponent(raw)
// https%3A%2F%2Fexample.com%2Fsearch%3Fq%3D%E4%B9%A6%E7%AD%BE%20%26%20page%3D2
// 连 : / ? & = 一起编码 —— 用来编码「一个参数值」
简单判断:
- 编码完整 URL(自己拼好的)→ 用
encodeURI; - 编码要插进 URL 的参数值 → 用
encodeURIComponent。
大部分 bug 都来自用错这一个函数。如果参数值里还嵌着 URL,基本上一定要用 encodeURIComponent。
空格到底是 %20 还是 + ?
两种都存在,区别是历史原因:
- 路径和标准规定用
%20; application/x-www-form-urlencoded(HTML 表单、很多查询解析器)把空格编码成+。
在路径里,+ 就是字面意义上的加号,不是空格。这就是"我的 + 怎么变成空格了"这类问题的根源:解析器把它当成表单编码数据了。
为什么会解码失败
decodeURIComponent('%E4%B9%A6') 正常,decodeURIComponent('%E4%B9') 会抛错,decodeURIComponent('100%') 也会——单独的 % 不是完整的转义序列。
遇到 URIError 时按顺序排查:
- 序列被截断:
%后面没有两个十六进制数字; - 编码了两遍:
%25E4...解一次得到%E4...,需要再解一次; - 层次搞错:解码了本来就没编码的内容,比如优惠码里的
%。
怎么在浏览器里编解码
URL 在线编解码工具 完全在浏览器本地运行,不上传、可离线。
- 选择「编码」或「解码」;
- 粘贴文本、URL 或已编码字符串;
- 点击「开始转换」(或按
Ctrl/⌘+Enter); - 把结果复制到代码或地址栏。
工具使用 encodeURIComponent / decodeURIComponent,正是处理查询参数值时需要的行为。
常见问题
应该编码整个 URL 还是只编码参数?
只编码"数据"部分。结构自己拼,每个值用 encodeURIComponent 编码。
为什么 %20 有时显示成 +?
表单编码用 + 表示空格。对接不同解析器时注意转换。
中文需要编码吗? 需要。中文不属于 ASCII,必须按 UTF-8 字节做百分号编码。
能手工解码吗? 短字符串可以查表,稍长一点还是用工具更靠谱。
相关阅读
- Base64 编码是什么?:另一种每天都遇到的编码
- 全部在线工具:免费、不上传、可离线
- NavProject:把常看的链接整理成自己的导航库