What percent-encoding does
A URL can only contain a limited set of ASCII characters, and some of those (/, ?, &, =, #) have structural meaning. Any other byte is written as a percent sign and two hex digits: a space is %20, & is %26, and the UTF-8 bytes of é are %C3%A9. RFC 3986 defines the rules.
Three modes, because context matters
| Mode | Escapes | Keeps | Use when |
|---|---|---|---|
| Query component | Everything except A–Z a–z 0–9 - _ . ~ | Only unreserved characters | Putting a value into a query parameter or path segment: ?q=…. Same as encodeURIComponent. |
| Whole URL | Spaces, non-ASCII, quotes, < >… | : / ? # [ ] @ & = + $ , ; | Cleaning up a complete URL without breaking its structure. Same as encodeURI. |
| Form data | As component, but space becomes + | Bodies of HTML forms (application/x-www-form-urlencoded), which is what most HTTP libraries send by default. |
The most common bug is using whole-URL encoding on a value that contains & or =: the server splits the parameter in two. Encode values with the component rules and only join them afterwards.
Plus signs
In a form body (and in the query string, by convention) + means a space, so decoding form data must turn + into a space while a literal plus must have been sent as %2B. In a path, + is just a plus. The Decode + as space switch covers both situations.
Double encoding
If you see %2520 in a URL, something encoded an already-encoded string: %20 was treated as text and its % became %25. Decode twice to recover the original, then fix the code that encoded twice.
Questions
What is %20?
A space. 0x20 is the ASCII code for space, so percent-encoding writes it as %20. In form data it may appear as + instead.
What is the difference between encodeURI and encodeURIComponent?
encodeURIComponent escapes every character that could be structural (including /, ?, & and =) and is for single values. encodeURI leaves those alone so a whole URL stays a URL. Use Query component mode for the former, Whole URL mode for the latter.
How are non-English characters encoded?
As the bytes of their UTF-8 form, each written as %XX. é is two bytes (%C3%A9), 日 is three (%E6%97%A5). Older systems sometimes used Latin-1, which gives %E9 for é; modern browsers and APIs use UTF-8.
Why does decoding fail on my string?
Either a % is not followed by two hex digits (a lone percent sign must be written as %25), or the escaped bytes do not form valid UTF-8. The error message says which.
Should I encode the whole URL or just the parameters?
Just the parameters (and any path segment that contains user text). Build the URL from already-encoded pieces so the delimiters stay unescaped.