← Back to all articles

URL Encoding: When You Need It, and Where %20 and + Come From

URLEncoding

Why encode at all

URLs only allow a limited character set. Chinese characters, spaces, &, =, ? and friends must be written as %XX sequences to travel safely, otherwise parsers mistake them for structural separators.

%20 vs +

Inside query strings (application/x-www-form-urlencoded) a space was historically written as +; in the URL path it can only be %20. Decoders disagree on how to treat +, which is where "my spaces turned into plus signs" bugs come from, prefer %20 for spaces in parameter values.

encodeURI vs encodeURIComponent

  • encodeURI: keeps URL structure characters (: / ? # [ ] @), use it for a whole URL;
  • encodeURIComponent: encodes aggressively, use it for individual parameter values.

Applying encodeURIComponent to a full URL encodes the :/ too and breaks the link, the most common misuse.

Two roots of Chinese mojibake

  1. Asymmetric encoding: encoded twice but decoded once (or the reverse), leaving %XX residue;
  2. Charset mismatch: sent as UTF-8 but parsed as GBK on the server, guaranteed mojibake.

Common characters and their encoding

CharacterEncodedNotes
Space%20 or +Query strings historically use +; paths must use %20
Non-ASCII letters%E4%B8%ADEach UTF-8 byte becomes one %XX
&%26Otherwise parsed as a parameter separator
=%3DMust be escaped inside parameter values
#%23Otherwise truncates the URL as a fragment

Code examples

// Frontend: always encodeURIComponent when building parameters
const url = '/search?q=' + encodeURIComponent('a b & c');
// => /search?q=a%20b%20%26%20c

// Node: new URLSearchParams({ q: 'a b & c' }).toString()
// Python: urllib.parse.quote('a b & c', safe='')

Three debugging tips

  1. When unsure, decode once first to check whether the value was encoded twice;
  2. On the server, confirm whether the framework decodes + as a space, in a URL path it is a literal plus;
  3. For non-ASCII mojibake, verify that both ends use UTF-8 before re-encoding anything.

Try them: URL codec, Base64 codec