HTML5 Guide
Web Standards & Network Protocol

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 bytes

Must 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:

  1. The character is converted to its UTF-8 byte sequence.
  2. Each byte is converted into a two-digit uppercase hexadecimal string.
  3. 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

CharacterASCII Hex CodePercent-EncodingSyntactical Role in URLs
(Space)0x20%20 (or + in queries)Whitespace separator; invalid raw in URLs.
/ (Slash)0x2F%2FPath segment separator. Must be encoded if part of a file name.
? (Question Mark)0x3F%3FBegins the query string parameters.
# (Hash)0x23%23Begins the client-side document fragment identifier.
& (Ampersand)0x26%26Separates query parameters in ?key1=val1&key2=val2.
= (Equals)0x3D%3DAssigns values to query parameter keys.
% (Percent)0x25%25The 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.

Frequently Asked Questions (FAQs)

Under RFC 3986, URLs are strictly limited to a subset of US-ASCII characters. Characters outside this set (accented letters, Cyrillic, Chinese, emojis) or characters with reserved syntactical roles (such as '?' for queries or '#' for fragments) would cause network routers, proxies, and web servers to misinterpret URI component boundaries. Percent-encoding translates arbitrary bytes into a universal '%HH' ASCII representation.

encodeURI() is designed to encode a complete URL; it intentionally leaves URI structural delimiters untouched (: / ? # & = +). In contrast, encodeURIComponent() is designed to encode a single query string key or value; it aggressively encodes delimiters (like '&' into %26 and '=' into %3D), preventing user input from prematurely splitting the query parameters.

In generic URL path components (e.g., /documents/my%20file.pdf), spaces must strictly be percent-encoded as %20 according to RFC 3986. However, in HTML form submissions encoded as 'application/x-www-form-urlencoded' (the query string portion ?query=hello+world), spaces are traditionally serialized as '+'. When writing client-side fetch calls, %20 is universally recognized across both paths and query strings.

Double encoding occurs when an already percent-encoded string is encoded a second time (e.g., %252F where %25 represents '%'). Attackers exploit double encoding to bypass Web Application Firewalls (WAFs) that inspect input only once: the WAF sees %252F as benign, but a downstream application decodes it twice, yielding a malicious '/' or path traversal ('../') attack.

Explore Related Tools

Hand-picked utilities and calculators related to this tool.

Related Tools