URL boundaries

URL encoding: encode data, not the whole address

A URL has structure: scheme, host, path, query, and fragment have different escaping rules. Encoding the full string usually destroys that structure.

Content updated: · Maintainer and corrections

Trace a query value through the URL API

Suppose the search text is tea & cake + milk. Set it as a value with url.searchParams.set("q", "tea & cake + milk"). Serialization produces q=tea+%26+cake+%2B+milk. Reading searchParams.get("q") returns the original text: the encoded ampersand stays inside the value, while a literal plus becomes %2B.

Paste the complete result into URL Inspector and compare its query with the original input. URLSearchParams uses form-style query encoding: its + represents a space. decodeURIComponent by itself does not turn + into a space, so it is not a drop-in query parser.

Trace a query value through the URL API
CaseInterpretation and next step
q=a&bThe unescaped & starts another parameter; use searchParams.set to retain it as data.
q=%2520One parse returns the literal text %20, not a space. Check whether the caller encoded twice.
#sectionThe fragment is not sent as part of the HTTP request target; do not store server-required input there.

Build from components

Start with a complete HTTP(S) URL, then change one path segment or query value at a time. This keeps separators such as ?, &, =, and / meaningful instead of turning them into data.

Spot double encoding

%20 already represents a space. Encoding it again produces %2520, which changes the value rather than making it safer. Decode only the component you intend to inspect, then encode it once at the boundary.

Parsing is not a security review

A syntactically valid URL can still point to an untrusted host or an unsafe redirect target. Apply an explicit allowlist and server-side validation before fetching, redirecting, or rendering external addresses.

https://example.test/search?q=tea%20set&lang=zh-TW

Data provenance

Sources