HTML URL Encoding: RFC 3986 Specifications, Percent-Encoding & Query Security
A Uniform Resource Identifier (URI / URL) specifies the location of a web resource over the internet. Because internet transport protocols (HTTP/1.1, HTTP/2, HTTP/3) rely on a restricted subset of ASCII characters, any characters falling outside this set—or carrying special syntactical meaning—must be converted via Percent-Encoding.
1. RFC 3986 Character Classification Matrix
Unreserved Characters
A-Z, a-z, 0-9, -, _, ., ~Always safe. Never require encoding in any portion of a URL.
Reserved Characters
: / ? # [ ] @ ! $ & ' ( ) * + , ; =Serve as syntactical delimiters separating scheme, host, path, query, and fragment. Must be encoded if used as data.
Unsafe & Unicode Characters
Space, ", <, >, %, UTF-8 bytesMust always be percent-encoded into hexadecimal byte triplets (%HH) before transmission.
2. Mechanics of Percent-Encoding
Percent-encoding operates on binary octets (bytes), not abstract characters. For non-ASCII characters:
- The character is converted to its UTF-8 byte sequence.
- Each byte is converted into a two-digit uppercase hexadecimal string.
- A percent sign (
%) is prepended to each byte.
Concrete Example: The Euro Symbol (€)
- Unicode Code Point:
U+20AC - UTF-8 Byte Sequence:
0xE2 0x82 0xAC(3 bytes) - Resulting URL Percent-Encoding:
%E2%82%AC
3. High-Frequency Percent-Encoding Reference Table
| Character | ASCII Hex Code | Percent-Encoding | Syntactical Role in URLs |
|---|---|---|---|
| (Space) | 0x20 | %20 (or + in queries) | Whitespace separator; invalid raw in URLs. |
/ (Slash) | 0x2F | %2F | Path segment separator. Must be encoded if part of a file name. |
? (Question Mark) | 0x3F | %3F | Begins the query string parameters. |
# (Hash) | 0x23 | %23 | Begins the client-side document fragment identifier. |
& (Ampersand) | 0x26 | %26 | Separates query parameters in ?key1=val1&key2=val2. |
= (Equals) | 0x3D | %3D | Assigns values to query parameter keys. |
% (Percent) | 0x25 | %25 | The escape prefix itself; must be encoded to avoid double decoding. |
4. JavaScript Implementation: encodeURI vs encodeURIComponent vs URLSearchParams
// 1. encodeURI(): Encodes a complete URL, preserving protocol and path slashes
const fullUrl = "https://example.com/search?category=books & journals";
console.log(encodeURI(fullUrl));
// Output: "https://example.com/search?category=books%20&%20journals"
// Notice: '?' and '&' are PRESERVED!
// 2. encodeURIComponent(): Encodes individual parameter keys or values
const queryParam = "shoes & shirts=50%";
console.log(encodeURIComponent(queryParam));
// Output: "shoes%20%26%20shirts%3D50%25"
// Notice: '&', '=', and '%' are SAFELY ENCODED!
// 3. Modern Recommended Standard: URLSearchParams API
const params = new URLSearchParams();
params.set("query", "Node.js & Next.js");
params.set("filter", "free & fast");
const safeUrl = `https://api.example.com/items?${params.toString()}`;
console.log(safeUrl);
// Output: "https://api.example.com/items?query=Node.js+%26+Next.js&filter=free+%26+fast"5. URL Security: Parameter Pollution & Path Traversal
❌ Parameter Injection
If an application concats raw strings: url + '&role=' + input, an attacker supplying admin&role=superadmin injects rogue query parameters. Always use URLSearchParams or encodeURIComponent.
❌ Path Traversal (%2E%2E%2F)
Encoded representations of ../ (such as %2e%2e%2f) are used by attackers to navigate out of public directories. Server software must normalize and validate paths after decoding.
