Lesson 5
The Plus Sign in Form Data
Why `+` sometimes means space and `%20` vs `+` in query strings.
Spaces in URLs historically caused trouble, so application/x-www-form-urlencoded (used by default HTML <form method="GET">) encodes spaces as + in the serialized body or query substring:
<form>
<input name="msg" value="hello world">
</form>
<!-- Submitted URL might contain: ?msg=hello+world -->
That is not the same rule as generic URI percent-encoding in every tooling path: many URI processors treat + as a literal plus unless explicitly using form-urlencoded semantics.
?msg=a+b // Might decode to "a b" OR "a+b" depending on parser mode
?q=city%20hall // Unambiguous URI percent-encoding for ASCII space (%20)
JavaScript helpers
URLSearchParams
const p = new URLSearchParams("a=b+c");
console.log(p.get("a")); // Likely interprets '+' as space in form mode
Creating from an object preserves form rules when stringifying:
new URLSearchParams({ tag: "a+b" }).toString(); // Might emit a%2Bb or tag=a%2Bb pattern depending on internals for '+'
console.log(String(new URLSearchParams({ expr: "1+2" })));
When you rely on interoperable literals, explicitly percent-encode plus signs (%2B) if they must survive as plus.
Manual decoding mistakes
Applying decodeURIComponent alone assumes percent sequences only—it does not convert '+':
decodeURIComponent('a+b'); // stays "a+b"
decodeURIComponent('a+b'.replace(/\+/g, " ")); // manual form-style fix—only when correct for your layer
Server frameworks
Popular stacks expose toggles (application/x-www-form-urlencoded parsers vs raw query parsers). Middleware order matters:
- Parse query as URI component semantics.
- Parse as HTML form semantics with
+→ space rules.
Misconfiguration causes bugs like hashed tokens breaking when '+' flips meanings between environments.
When to encode what
| Need | Recommendation |
|---|---|
Literal '+' in a form field value crossing URL | Encode %2B at value layer |
Human-readable '+' in JSON transport | Prefer JSON bodies, not queries |
| Debug logging | Capture raw bytes (req.url) before parsers rewrite |
Understanding + helps you classify bugs: duplicate decoding, mismatched parsers, versus genuine user input needing %2B. Pair this mindset with Lesson 4’s warning about brittle split('&') after partial decoding.