Percent-encode and decode URLs and query components correctly.
Percent-encoding (or URL encoding) replaces characters that aren't allowed or that have special meaning in a URL with %XX, where XX is the hexadecimal value of the UTF-8 byte. JavaScript provides two encoding levels. encodeURIComponent is for individual components: query parameter names, query parameter values, or path segments. It encodes everything except A–Z, a–z, 0–9, and - _ . ! ~ * ' ( ). encodeURI is for a complete URL — it additionally leaves : / ? # [ ] @ ! $ & ' ( ) * + , ; = unencoded because they are structural characters in a URL. Mixing them up is a common source of broken links and injection vulnerabilities.
Percent-encoding
Each unsafe byte is encoded as %XX where XX is the two-digit uppercase hex value of the UTF-8 byte.
Always use encodeURIComponent for individual query values. For example, to build ?q=hello world&lang=en use encodeURIComponent('hello world') which gives 'hello%20world'. If you used encodeURI instead, the space would still be encoded but = and & would not, making the URL ambiguous.
+ for spaces is the application/x-www-form-urlencoded encoding used by HTML forms and some older APIs. It is not the same as standard percent-encoding (RFC 3986). decodeURIComponent will not turn + back into a space — that requires a separate replace('+', ' '). When in doubt, %20 is unambiguous and works everywhere.
Yes — double-decoding is a security vulnerability. If a server decodes a URL twice, an attacker can encode a path traversal ('../') as '%252e%252e%252f' (which decodes to '%2e%2e%2f' on the first pass, then '../' on the second). Always decode exactly once at a single, well-defined point in your request pipeline.
Only in query strings using application/x-www-form-urlencoded (HTML forms). In standard RFC 3986 percent-encoding, + is a literal plus sign and %2B is also a literal plus sign. If you want a literal + in a query parameter, encode it as %2B with encodeURIComponent.