为什么必须编码?
HTTP 协议规定 URL 中只能包含 ASCII 字符,非 ASCII 字符(如汉字)和保留字符(如空格、&、= 等)必须进行 百分号编码(URL encoding),否则:
- 空格会被服务器误认为分隔符或被截断
- 汉字可能被解析为乱码,甚至导致请求失败
- 参数分隔符(
&、=)会被误认为结构符号,破坏参数结构
不同场景的编码规则
1. GET 请求(URL 查询字符串)
必须编码 。
例如,将 name=张三 city=北京 拼接到 URL 中:
javascript
// 错误(未编码)
fetch('/api?name=张三&city=北京') // 可能无法正确解析
// 正确
const name = encodeURIComponent('张三');
const city = encodeURIComponent('北京');
fetch(`/api?name=${name}&city=${city}`);
编码后:
/api?name=%E5%BC%A0%E4%B8%89&city=%E5%8C%97%E4%BA%AC
2. POST 请求(application/x-www-form-urlencoded)
必须编码 。
这是表单默认的编码格式,参数以 key=value 形式放在请求体中,同样要求 URL 编码。
javascript
// 使用 URLSearchParams 自动编码
const body = new URLSearchParams();
body.append('name', '张三');
body.append('city', '北京');
fetch('/api', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: body
});
实际发送的 body 为:
name=%E5%BC%A0%E4%B8%89&city=%E5%8C%97%E4%BA%AC
3. POST 请求(multipart/form-data,常用于文件上传)
不需要手动编码 。
浏览器会自动处理每个字段的编码(包含汉字和空格),且二进制数据原样传输。
javascript
const formData = new FormData();
formData.append('name', '张三 李四'); // 空格保留
formData.append('file', fileInput.files[0]);
fetch('/api', {
method: 'POST',
body: formData // 浏览器自动设置 Content-Type 并编码
});
4. POST 请求(application/json)
不需要编码 。
JSON 本身支持 Unicode,汉字和空格直接作为字符串传输。
javascript
fetch('/api', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: '张三 李四' })
});
库的自动处理
- Axios :默认对
params(GET 参数)和application/x-www-form-urlencoded的data自动编码。 - jQuery AJAX :
$.ajax的data对象会被自动编码(若未指定contentType: false)。 - Fetch :
URLSearchParams和FormData会编码,但手动拼接 URL 需自己调用encodeURIComponent。 - XHR :手动拼接时需调用
encodeURIComponent。
总结
| 请求类型 | 数据位置 | 格式 | 是否必须编码 | 说明 |
|---|---|---|---|---|
| GET | URL | 查询字符串(query string) | ✅ 必须 | 所有非 ASCII 和保留字符都需百分号编码 |
| POST | Body | application/x-www-form-urlencoded |
✅ 必须 | 同 GET 规则 |
| POST | Body | multipart/form-data |
❌ 不需要 | 浏览器自动处理,各字段独立边界分隔 |
| POST | Body | application/json |
❌ 不需要 | JSON 原生支持 Unicode |
最佳实践 :永远不要手动拼接 URL 参数而不编码。使用现代库或 URLSearchParams 等 API 让浏览器/库自动处理。