A URL (Uniform Resource Locator) is the global address used by web browsers and HTTP clients to locate and retrieve documents, media, and web services across the Internet. Because the fundamental networking protocols of the World Wide Web were designed exclusively around the 7-bit US-ASCII character set, any character that falls outside this range—or any character reserved as structural syntax—must be converted into a universally safe format through a process known as URL Encoding or Percent-Encoding (standardized under RFC 3986).
Before exploring encoding mechanics, it is essential to understand the individual structural components that make up a complete Uniform Resource Locator:
https://www.veewom.com:443/tutorials/html/search.php?query=web+design&lang=en#results
\___/ \____________/ \__/ \______________________/ \______________________/ \_____/
| | | | | |
Scheme Host/Domain Port Path Query String Fragment
Each segment performs a distinct role in routing and resource identification:
https://, http://, mailto:, ftp://).www.veewom.com or 192.168.1.1).80 for HTTP and 443 for HTTPS if omitted)./tutorials/html/search.php).? and delimited by & (e.g., ?query=web+design&lang=en).# (e.g., #results).Different schemes instruct the client browser on which protocol handler and security handshake to initiate:
| Scheme | Full Name | Default Port | Usage & Encryption Standard |
|---|---|---|---|
https:// |
Hypertext Transfer Protocol Secure | 443 | Standard encrypted web traffic using TLS/SSL. Protects data in transit. |
http:// |
Hypertext Transfer Protocol | 80 | Legacy unencrypted plaintext web communication. (Deprecated for modern sites). |
ftp:// / sftp:// |
File Transfer Protocol / Secure FTP | 21 / 22 | Direct uploading and downloading of bulk files between client and server. |
mailto: |
Electronic Mail Address | N/A | Opens default email client with recipient (e.g., mailto:contact@veewom.com). |
tel: |
Telephone Call URI | N/A | Launches phone dialer on smartphones and VOIP clients (e.g., tel:+1234567890). |
data: |
Data URI Scheme | N/A | Embeds inline base64-encoded media directly within HTML or CSS. |
URLs are transmitted over the Internet using the standard 128-character US-ASCII character set (codes 0 to 127). Characters outside this range—such as accented letters, non-Latin scripts (Hindi, Japanese, Arabic), mathematical symbols, and emoji—cannot be transmitted directly over raw HTTP headers without corruption.
Furthermore, certain ASCII characters are syntactically reserved by the URI specification to serve as structural delimiters. If user input contains a delimiter character (such as ?, &, or =), the browser or server parser would mistake it for structural syntax unless it is converted into its escaped hexadecimal byte representation.
Percent-encoding replaces unsafe or reserved characters with a percent sign (%) followed immediately by two hexadecimal digits representing the character's byte value in the chosen encoding (modern standards mandate UTF-8):
20) → encoded as %20.&) (ASCII 38, hex 26) → encoded as %26.0xE2 0x82 0xAC) → encoded as %E2%82%AC.Under RFC 3986, characters are classified into two critical categories:
These characters have no syntactic meaning in URLs and should never be percent-encoded:
| Character Category | Permitted Characters | Description |
|---|---|---|
| Uppercase Letters | A - Z |
English uppercase alphabetic characters (ASCII 65–90). |
| Lowercase Letters | a - z |
English lowercase alphabetic characters (ASCII 97–122). |
| Digits | 0 - 9 |
Standard decimal digits (ASCII 48–57). |
| Safe Punctuation Marks | - _ . ~ |
Hyphen, Underscore, Period (Dot), and Tilde. |
These characters serve as structural delimiters. If they appear inside a parameter value or filename, they must be encoded so they are not misinterpreted as URL syntax:
| Character | Percent Code | Structural Delimiter Purpose |
|---|---|---|
: (Colon) | %3A | Separates scheme from path, or host from port. |
/ (Slash) | %2F | Separates hierarchical path segments. |
? (Question Mark) | %3F | Marks the beginning of the query string. |
# (Hash / Fragment) | %23 | Marks the beginning of the document fragment/anchor. |
& (Ampersand) | %26 | Separates distinct parameter pairs in a query string. |
= (Equals) | %3D | Separates a parameter key from its assigned value. |
+ (Plus) | %2B | Often represents an encoded space in form submissions; literal plus must be %2B. |
@ (At sign) | %40 | Precedes user credentials in legacy URLs (user:pass@host). |
[ and ] | %5B and %5D | Used for IPv6 literal host addresses. |
This master table lists commonly encountered symbols and their standard percent-encoded values for fast reference:
| Symbol | Character Name | ASCII Hex | Percent-Encoded URL Value |
|---|---|---|---|
| Space | 0x20 | %20 (or + in form data) |
! | Exclamation Point | 0x21 | %21 |
" | Double Quotation Mark | 0x22 | %22 |
# | Number Sign (Hash) | 0x23 | %23 |
$ | Dollar Sign | 0x24 | %24 |
% | Percent Sign | 0x25 | %25 |
& | Ampersand | 0x26 | %26 |
' | Single Quotation Mark | 0x27 | %27 |
( | Left Parenthesis | 0x28 | %28 |
) | Right Parenthesis | 0x29 | %29 |
* | Asterisk | 0x2A | %2A |
+ | Plus Sign | 0x2B | %2B |
, | Comma | 0x2C | %2C |
/ | Forward Slash | 0x2F | %2F |
: | Colon | 0x3A | %3A |
; | Semicolon | 0x3B | %3B |
< | Less-Than Sign | 0x3C | %3C |
= | Equals Sign | 0x3D | %3D |
> | Greater-Than Sign | 0x3E | %3E |
? | Question Mark | 0x3F | %3F |
@ | Commercial At | 0x40 | %40 |
[ | Left Square Bracket | 0x5B | %5B |
\ | Backslash | 0x5C | %5C |
] | Right Square Bracket | 0x5D | %5D |
^ | Caret | 0x5E | %5E |
` | Grave Accent (Backtick) | 0x60 | %60 |
{ | Left Curly Bracket | 0x7B | %7B |
| | Vertical Bar (Pipe) | 0x7C | %7C |
} | Right Curly Bracket | 0x7D | %7D |
~ | Tilde | 0x7E | ~ (Unreserved in RFC 3986) |
%20 vs. + ExplainedWeb developers frequently encounter both %20 and + representing spaces. Here is why the distinction matters:
%20. Example: https://example.com/my%20documents/file.pdf.application/x-www-form-urlencoded): When an HTML <form method="GET"> is submitted, spaces within form fields are converted to plus signs (+). Example: search.php?query=html+tutorial.%20) is universally accepted and avoids ambiguity.encodeURI() vs. encodeURIComponent()JavaScript provides two native built-in global functions for encoding URLs. Understanding when to use each is one of the most common web development interview questions:
| Feature | encodeURI(uriString) |
encodeURIComponent(componentString) |
|---|---|---|
| Intended Purpose | Encodes a complete, full URL without breaking protocol and path syntax. | Encodes an individual parameter key or value destined for a query string. |
| Does NOT Encode | : / ; ? & = + $ , # |
Only unreserved: A-Z a-z 0-9 - _ . ! ~ * ' ( ) |
Encodes / and ? and &? |
NO (Preserves URL structure) | YES (Encodes them to %2F, %3F, %26) |
| Example Use Case | encodeURI("https://veewom.com/search?topic=web design") |
"https://veewom.com/search?title=" + encodeURIComponent("C & C++ Guide") |
<script>
const baseUrl = "https://veewom.com/search";
const userQuery = "HTML & CSS: What's New?";
// WRONG: encodeURI does not encode '&' or ':', corrupting the query parameter
const badUrl = encodeURI(baseUrl + "?query=" + userQuery);
console.log("badUrl:", badUrl);
// Output: https://veewom.com/search?query=HTML%20&%20CSS:%20What's%20New?
// Server will see two parameters: 'query'='HTML ' and ' CSS: What's New?'
// CORRECT: encodeURIComponent safely encodes special parameter delimiters
const goodUrl = baseUrl + "?query=" + encodeURIComponent(userQuery);
console.log("goodUrl:", goodUrl);
// Output: https://veewom.com/search?query=HTML%20%26%20CSS%3A%20What's%20New%3F
</script>
Scenario: Create a responsive web application that lets students enter a base URL and custom query parameter keys and values containing spaces, ampersands, and punctuation. The script must compare the output of raw text, encodeURI(), and encodeURIComponent(), generating a safe, clickable hyperlink.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Interactive URL Encoder & Query Builder</title>
<style>
body { font-family: Arial, sans-serif; margin: 30px; background: #f8f9fa; }
.box { background: #fff; padding: 25px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); max-width: 700px; }
label { font-weight: bold; display: block; margin-top: 12px; }
input[type="text"] { width: 100%; padding: 8px; margin-top: 5px; box-sizing: border-box; border: 1px solid #ccc; border-radius: 4px; }
button { background: #007bff; color: white; padding: 10px 18px; border: none; border-radius: 4px; cursor: pointer; margin-top: 15px; font-weight: bold; }
button:hover { background: #0056b3; }
.result { background: #e9ecef; padding: 12px; border-left: 4px solid #007bff; margin-top: 15px; word-break: break-all; font-family: monospace; }
</style>
</head>
<body>
<div class="box">
<h2>URL Percent-Encoding Tool</h2>
<label for="baseUrl">Base URL:</label>
<input type="text" id="baseUrl" value="https://veewom.com/search.php">
<label for="paramKey">Parameter Key:</label>
<input type="text" id="paramKey" value="topic">
<label for="paramValue">Parameter Value (Try symbols like &, ?, =, space):</label>
<input type="text" id="paramValue" value="HTML5 & CSS3: Beginners Guide">
<button type="button" onclick="generateSafeUrl()">Build & Encode Safe URL</button>
<h3 style="margin-top:20px;">Encoding Results:</h3>
<p><strong>Raw (Unsafe):</strong></p>
<div id="rawResult" class="result">Waiting for input...</div>
<p><strong>Safely Encoded with encodeURIComponent():</strong></p>
<div id="encodedResult" class="result">Waiting for input...</div>
<p id="linkContainer" style="margin-top:15px;"></p>
</div>
<script>
function generateSafeUrl() {
const base = document.getElementById("baseUrl").value.trim();
const key = document.getElementById("paramKey").value.trim();
const val = document.getElementById("paramValue").value.trim();
// Unsafe direct concatenation
const unsafeUrl = base + "?" + key + "=" + val;
document.getElementById("rawResult").innerText = unsafeUrl;
// Safe percent encoding
const safeKey = encodeURIComponent(key);
const safeVal = encodeURIComponent(val);
const safeUrl = base + "?" + safeKey + "=" + safeVal;
document.getElementById("encodedResult").innerText = safeUrl;
// Clickable test link
document.getElementById("linkContainer").innerHTML =
'<a href="' + safeUrl + '" target="_blank" style="color: #28a745; font-weight: bold;">Click to Test Safe URL →</a>';
}
</script>
</body>
</html>
%) followed by two hexadecimal digits (e.g., space becomes %20, and & becomes %26).
encodeURI() is designed to encode an entire URI and intentionally leaves URI delimiters intact (such as :, /, ?, #, &, =). In contrast, encodeURIComponent() is designed to encode individual parameter keys and values; it encodes delimiters (like &, =, /, ?) into their percent codes so that user data cannot accidentally alter the URL structure.
%20. However, the W3C standard for HTML form data submission (MIME type application/x-www-form-urlencoded) historically adopted the plus sign (+) to represent spaces in query strings. Modern web servers and URL decoders recognize both representations.
A-Z), lowercase English letters (a-z), decimal digits (0-9), and four punctuation marks: hyphen (-), underscore (_), period (.), and tilde (~).
€) consists of three bytes in UTF-8: 0xE2 0x82 0xAC, resulting in the percent-encoded sequence %E2%82%AC.
&) injected by a malicious user allows them to append unauthorized parameters (e.g., &role=admin) to the destination request.
%20, spaces in file names frequently cause broken links in legacy scripts, command-line tools (cURL, wget), Markdown parsers, and web servers. Always use hyphens (e.g., web-development-notes.pdf) instead of spaces.
URLSearchParams interface automatically handles percent-encoding and formatting. For example:
<script>
const params = new URLSearchParams({ search: "HTML & CSS", page: 1 });
console.log(params.toString()); // Outputs: "search=HTML+%26+CSS&page=1"
</script>
This completely eliminates manual string concatenation and accidental encoding mistakes.
%) is itself encoded as %25. For example, if %20 is encoded again, it becomes %2520. When decoded by the server, it results in the literal text %20 rather than an actual space.