← All guides

Understanding URL encoding and percent-encoding

Why a space becomes %20 in one place and a plus sign in another, how double encoding happens, and why you must never encode a whole URL.

url encode url decode percent encoding 쿼리스트링

Why URLs restrict characters

The URL specification allows only a limited character set: letters, digits, and a handful of marks such as hyphen, underscore, period, and tilde.

There are two reasons. First, a URL passes through many environments beyond the address bar, including email bodies, log files, and protocol headers, and the set of characters handled safely everywhere is narrow. Second, characters such as question mark, ampersand, equals, hash, and slash already have structural meaning as delimiters.

When a value contains one of those delimiters, the address is parsed incorrectly. If a search term is a&b and you send q=a&b without encoding, the server reads a value of a plus a separate parameter named b.

How percent-encoding works

Percent-encoding splits a character into bytes and writes each byte as a percent sign followed by two hexadecimal digits. A space becomes %20 and a question mark becomes %3F.

The key point is that bytes are encoded, not characters. Many non-ASCII characters occupy three bytes in UTF-8, so a single character becomes three percent groups. That is why a two-character Korean word turns into six groups.

The result therefore depends entirely on the source encoding. Most corruption problems when integrating with legacy systems start here, where one side assumes UTF-8 and the other assumes something else.

The difference between %20 and plus

Having two conventions for encoding a space causes more confusion than anything else in this area.

General URL encoding under RFC 3986, which is what JavaScript encodeURIComponent implements, produces %20. The application/x-www-form-urlencoded format used by HTML form submission produces a plus sign instead.

The difficulty is that both appear within the same URL: some servers use %20 in the path and a plus in the query string. If a value must contain a literal plus sign, it has to be encoded as %2B, otherwise the receiving side reads it as a space.

Never encode an entire URL

A frequent mistake is encoding a fully assembled URL. The slashes in https:// become %2F and the ampersands separating parameters become %26, which destroys the address.

Encoding belongs to individual parameter values. Encode each value first, then join them with question mark, ampersand, and equals.

The exception is passing a URL as a parameter of another URL, such as a redirect_uri after login. There the entire inner URL is a single value, so encoding it as a whole is exactly right.

Double encoding

Encoding an already encoded string turns the percent sign itself into %25, so %ED%95%9C becomes %25ED%2595%259C.

This happens in systems with several layers: the frontend encodes a value, a framework encodes it again, or a proxy re-processes it in transit. The symptom is a value that grows unexpectedly long with %25 sequences appearing in it.

The fix is to identify which layer performs the encoding and remove the duplication. Decoding twice recovers the original as a stopgap, but consolidating encoding into a single place is the real solution.

Tools covered in this guide

Copied