DEV Community

jiebang-tools
jiebang-tools

Posted on

URL Encoding & Decoding in JavaScript: A Practical Guide with Real Examples

If you've ever seen %20 in a URL and wondered what it means, or had your app crash because a user's name contained a & symbol, you're in the right place. URL encoding is one of those fundamentals that every web developer needs to understand — but few truly master.

In this guide, we'll break down how URL encoding works, when to use encodeURIComponent vs encodeURI, and how to handle edge cases that trip up even experienced developers.


What Is URL Encoding?

URLs can only contain a limited set of ASCII characters: letters, digits, and a few special characters like -, _, ., and ~. Anything outside this set — spaces, Chinese characters, emojis, even some punctuation — must be percent-encoded.

The encoding replaces each unsafe character with % followed by two hexadecimal digits representing the character's byte value in UTF-8.

For example:

  • Space → %20
  • &%26
  • %E4%B8%AD
  • 🎉%F0%9F%8E%89

JavaScript's Built-in Encoding Functions

JavaScript provides two main functions for URL encoding, and choosing the wrong one is a common source of bugs.

encodeURI

Use this when you want to encode a complete URL. It preserves characters that have special meaning in URLs, such as :, /, ?, #, &, and =.

const url = 'https://example.com/search?q=hello world&lang=zh';
const encoded = encodeURI(url);
// Result: https://example.com/search?q=hello%20world&lang=zh
Enter fullscreen mode Exit fullscreen mode

Notice that ://, ?, and & are preserved — only the space was encoded.

encodeURIComponent

Use this when you want to encode a single component of a URL, like a query parameter value. This function encodes everything except A-Z, a-z, 0-9, -, _, ., !, ~, *, ', (, and ).

const param = 'hello world & goodbye';
const encoded = encodeURIComponent(param);
// Result: hello%20world%20%26%20goodbye
Enter fullscreen mode Exit fullscreen mode

Here, the & is encoded to %26 — exactly what you want when building query strings.

The Golden Rule

Use encodeURIComponent for individual parameter values. Use encodeURI only when encoding an entire URL that's already well-formed.


Building Query Strings Safely

Here's a pattern I use in production code:

function buildQueryString(params) {
  return Object.entries(params)
    .map(([key, value]) => 
      `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
    )
    .join('&');
}

const qs = buildQueryString({
  search: 'JavaScript 教程',
  page: 2,
  filter: 'price < 100 & in stock'
});
// Result: search=JavaScript%20%E6%95%99%E7%A8%8B&page=2&filter=price%20%3C%20100%20%26%20in%20stock
Enter fullscreen mode Exit fullscreen mode

This ensures every key and value is independently encoded, preventing injection issues.


Decoding URLs

JavaScript also provides two corresponding decode functions:

decodeURI

Decodes a string that was encoded with encodeURI. It won't decode characters like %2F (which represents /) because / is a valid URL character.

const encoded = 'https://example.com/search?q=hello%20world';
const decoded = decodeURI(encoded);
// Result: https://example.com/search?q=hello world
Enter fullscreen mode Exit fullscreen mode

decodeURIComponent

Decodes a string that was encoded with encodeURIComponent. It will decode everything.

const encoded = 'hello%20world%20%26%20goodbye';
const decoded = decodeURIComponent(encoded);
// Result: hello world & goodbye
Enter fullscreen mode Exit fullscreen mode

Common Pitfalls (and How to Avoid Them)

1. Double Encoding

This happens when you encode a value that's already been encoded:

const url = 'https://example.com/?q=hello%20world';
const bad = encodeURI(url);
// Result: https://example.com/?q=hello%2520world  ← The % got encoded!

const good = encodeURI('https://example.com/?q=hello world');
// Result: https://example.com/?q=hello%20world  ← Correct
Enter fullscreen mode Exit fullscreen mode

Fix: Always encode raw values, never re-encode.

2. Mixing Up the Two Functions

// ❌ Wrong: encodeURI won't encode & so your parameter value gets split
const url = `https://api.example.com?name=${encodeURI('Tom & Jerry')}`;
// Result: https://api.example.com?name=Tom%20&%20Jerry  ← The & breaks the query string!

// ✅ Correct: use encodeURIComponent for parameter values
const url = `https://api.example.com?name=${encodeURIComponent('Tom & Jerry')}`;
// Result: https://api.example.com?name=Tom%20%26%20Jerry  ← 
Enter fullscreen mode Exit fullscreen mode

3. Forgetting About + for Spaces

In application/x-www-form-urlencoded (used in form POST data), spaces are encoded as + instead of %20. JavaScript's encodeURIComponent uses %20, which is valid in URLs but not in form data.

// For form data, replace %20 with +
const formData = encodeURIComponent('hello world').replace(/%20/g, '+');
// Result: hello+world
Enter fullscreen mode Exit fullscreen mode

Or use URLSearchParams, which handles this automatically:

const params = new URLSearchParams({ name: 'hello world' });
params.toString();
// Result: name=hello+world
Enter fullscreen mode Exit fullscreen mode

Modern Alternative: URLSearchParams

For most use cases, URLSearchParams is the cleanest approach:

const params = new URLSearchParams({
  search: 'JavaScript 指南',
  page: '1',
  sort: 'desc'
});

const queryString = params.toString();
// Result: search=JavaScript+%E6%8C%87%E5%8D%97&page=1&sort=desc

const url = `https://example.com/search?${queryString}`;
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Automatically encodes keys and values
  • Handles + for spaces correctly
  • Provides methods like .get(), .set(), .append(), .has()
  • Well-supported in all modern browsers and Node.js

Practical Example: Building an API Request

Let's put it all together with a real-world example:

async function searchProducts(query, filters) {
  const params = new URLSearchParams({
    q: query,
    ...filters
  });

  const response = await fetch(`https://api.example.com/products?${params}`);

  if (!response.ok) {
    throw new Error(`API error: ${response.status}`);
  }

  return response.json();
}

// Usage
searchProducts('无线耳机', { 
  min_price: '100', 
  max_price: '500',
  category: '数码 & 电子'  // The & is safely encoded
}).then(console.log);
Enter fullscreen mode Exit fullscreen mode

Quick Reference Table

Character encodeURI encodeURIComponent
Space %20 %20
& & %26
= = %3D
? ? %3F
/ / %2F
# # %23
%E4%B8%AD %E4%B8%AD

Summary

  • Use encodeURIComponent for individual query parameter values
  • Use encodeURI only for complete URLs that are already well-formed
  • Prefer URLSearchParams for building query strings in modern code
  • Never double-encode — always encode raw values
  • For form POST data, spaces should be + not %20

If you want to test URL encoding/decoding interactively, I've built a free online URL encoder/decoder tool that supports UTF-8 and handles all edge cases. It's 100% client-side — your data never leaves your browser.


Found this helpful? Follow me for more practical JavaScript guides. Questions? Drop a comment below!

Top comments (0)