第 5 课

表单中的加号问题

为何 `+` 有时表示空格,以及 `%20` 与 `+` 的差异。

默认的 HTML <form method="GET"> 会把字段序列化成 application/x-www-form-urlencoded 风格:空格常被写成 +(出现在提交后的 URL query 片段里很常见):

<form>
  <input name="msg" value="hello world">
</form>
<!-- 提交后可能出现:?msg=hello+world -->

这与你在 任意 URI 解析器 里遇到的规则 未必相同。有的实现把 query 当成纯 URI component:此时 + 就是字面加号,只有按 表单规则解析时,+ 才会被解释为 ASCII 空格

?msg=a+b        // 在「表单语义」里常解读为「a」+空格+「b」;在「纯 URI」语义里可能只是三个字符 a,+ ,b

?q=city%20hall  // 明确表示 ASCII 空格,多数 URI 语义下更不易歧义

JavaScript 中的典型行为

URLSearchParams

const p = new URLSearchParams("a=b+c");
console.log(p.get("a")); // 常按表单习惯把 '+' 当作空格解码

当键值里 真的需要字面加号(例如算术式、Base64、A+B 时,构建阶段应改用 %2B,避免在中间层被误换。

const usp = new URLSearchParams();
usp.set("expr", "1+2");
console.log(usp.toString()); // 具体输出可能因实现细节略有差异,但关键是:「+」是否被当作格式字符

只用 decodeURIComponent 的误区

decodeURIComponent 只处理 %HH不会+ 变成空格:

decodeURIComponent("a+b"); // 仍是 "a+b"

// 只有当你明确处于「表单解码层」时,才可能先做:
"a+b".replace(/\+/g, " ");

把这两步混在同一层,很容易在网关 / 应用之间产生 二次替换该换没换

服务端与中间件

各语言框架常会区分:

  • 「querystring 原始解析」;
  • application/x-www-form-urlencoded 解析(含 + → 空格)」。

流水线顺序颠倒时,常见问题包括:令牌、签名载荷里的 + 被静默改写,staging 与 production 解析模式不一致。

实用对照

目标建议
字面量必须是加号并通过 URL/query 传输在取值层写成 %2B
复杂结构化数据优先考虑 JSON 请求体,而不是把一切塞进查询串
线上排障同时记录 ? 后面的原始字节 与各层解析后的对象

弄清 + 属于 表单编码约定而非「URI 天生如此」,就能把不少「环境里正常、环境里挂」的差异定位到具体的解析语义上;并与第 4 课强调的 分界与分层编码 一起使用。

想动手练习时,可使用 DevCove 相关工具——可选,不属于本课正文。

打开相关工具

返回课程概览