Complete Guide to URL Encoding - Solving Character Encoding and Special Character Issues
Why do Korean characters break and special characters cause errors in API calls? Learn the difference between encodeURI vs encodeURIComponent and practical solutions.
Toolypet Team
Development Team
Complete Guide to URL Encoding
"I sent Korean parameters to the API and they came back garbled."
Sent: ?name=John Doe
Received: ?name=John%20Doe
The cause of this issue is URL encoding. Understanding it properly means you'll never struggle with broken characters again.
Why Encoding is Necessary
URLs were created in the 1990s and only allow ASCII characters.
Safe Characters in URLs
A-Z a-z 0-9 - _ . ~
That's all.
Problematic Characters in URLs
| Character | Problem |
|---|---|
| Non-ASCII | Not ASCII characters |
| Space | Interpreted as URL delimiter |
& | Parameter separator |
? | Query string start |
= | Key-value separator |
# | Fragment start |
/ | Path separator |
What Encoding Does
Converts problematic characters to %XX format (hexadecimal).
Space -> %20
& -> %26
e -> %65 (though safe, as example)
JavaScript Encoding Functions
Key Differences
const text = "hello world&name=John Doe";
encodeURI(text);
// "hello%20world&name=John%20Doe"
// & and = remain intact (preserves URL structure)
encodeURIComponent(text);
// "hello%20world%26name%3DJohn%20Doe"
// & -> %26, = -> %3D (encodes everything)
When to Use Which
| Situation | Function | Reason |
|---|---|---|
| Query parameter value | encodeURIComponent | Must encode &, = |
| Entire URL | encodeURI | Preserve URL structure |
| Path segment | encodeURIComponent | Must encode / |
Common Mistakes
// Wrong: encodeURIComponent on entire URL
const url = "https://api.com/search?q=test";
encodeURIComponent(url);
// "https%3A%2F%2Fapi.com%2Fsearch%3Fq%3Dtest"
// Not usable as URL!
// Correct: Only encode the value
const query = "test";
const url = `https://api.com/search?q=${encodeURIComponent(query)}`;
// "https://api.com/search?q=test"
URLSearchParams - The Modern Way
Use URLSearchParams instead of manual encoding.
Basic Usage
const params = new URLSearchParams({
name: "John Doe",
city: "New York City",
tags: "developer,frontend"
});
params.toString();
// "name=John+Doe&city=New+York+City&tags=developer%2Cfrontend"
Encoding happens automatically. No room for mistakes.
With URL Object
const url = new URL("https://api.com/search");
url.searchParams.set("q", "John Doe");
url.searchParams.set("page", 1);
url.toString();
// "https://api.com/search?q=John+Doe&page=1"
Parsing (Decoding)
const url = new URL("https://api.com/search?name=John%20Doe");
url.searchParams.get("name"); // "John Doe" <- auto-decoded!
Practical Problem Solving
Problem 1: Double Encoding
// Encoding an already encoded value
const encoded = "%20";
encodeURIComponent(encoded);
// "%2520"
// % -> %25 causing complete corruption
Solution: Check if already encoded before encoding
function safeEncode(str) {
try {
// If already encoded, decode first then re-encode
return encodeURIComponent(decodeURIComponent(str));
} catch {
// Decode failure = not encoded yet
return encodeURIComponent(str);
}
}
Problem 2: Two Faces of Space
%20 vs +
Both represent space but have different origins.
| Method | Usage |
|---|---|
%20 | URL standard (RFC 3986) |
+ | HTML forms (application/x-www-form-urlencoded) |
encodeURIComponent("hello world"); // "hello%20world"
new URLSearchParams({q: "hello world"}).toString(); // "q=hello+world"
Both are processed correctly by servers. But choose one method for consistency.
Problem 3: Framework Already Encodes
axios, fetch, React Router, etc. automatically encode.
// axios - auto encoding
axios.get('/search', { params: { name: 'John Doe' } });
// Request: /search?name=John%20Doe
// Wrong: Manual encoding causes double encoding
axios.get('/search', { params: { name: encodeURIComponent('John Doe') } });
// Request: /search?name=John%2520Doe (broken)
Rule: If using a framework, don't encode manually.
Server-Side Handling
Node.js / Express
// Auto-decoded
app.get('/search', (req, res) => {
const name = req.query.name; // "John Doe"
});
// Same for path parameters
app.get('/users/:name', (req, res) => {
const name = req.params.name; // "John Doe"
});
Python / Flask
from flask import request
@app.route('/search')
def search():
name = request.args.get('name') # "John Doe"
PHP
$name = $_GET['name']; // "John Doe"
// PHP also auto-decodes
Special Cases
Base64 in URL
Standard Base64 contains +, /, = which cause problems in URLs.
// Standard Base64
btoa("hello"); // "aGVsbG8="
// URL-safe Base64
function base64UrlEncode(str) {
return btoa(str)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, ''); // remove padding
}
base64UrlEncode("hello"); // "aGVsbG8"
JWT uses this format.
Fragment (#) Caution
https://example.com/page?name=John#section
^
Not sent to server from here
Everything after # (fragment) is processed only in the browser and not sent to the server.
Debugging Tips
Browser Address Bar
Browsers show decoded URLs for readability.
Displayed: https://example.com/users/John Doe
Actual: https://example.com/users/John%20Doe
Check the actual request URL in Developer Tools Network tab.
Testing with curl
# Direct encoded URL
curl "https://api.com/search?name=John%20Doe"
# Let curl encode
curl -G "https://api.com/search" --data-urlencode "name=John Doe"
Summary
| Situation | Solution |
|---|---|
| Creating query parameters | Use URLSearchParams |
| Encoding values only | encodeURIComponent |
| Encoding entire URL | encodeURI |
| Using a framework | Don't encode manually |
| Broken characters | Suspect double encoding |
Core Principle: Whenever possible, let URLSearchParams or your framework handle it, and avoid manual encoding.
Related Tools
| Tool | Purpose |
|---|---|
| URL Encoder | Encoding/Decoding |
| URL Parser | URL structure analysis |
| Base64 | Base64 conversion |
About the Author
Toolypet Team
Development Team
The Toolypet Team creates free, privacy-focused web tools for developers and designers. All tools run entirely in your browser with no data sent to servers.