Every request starts from a URL, and many bugs come from building or encoding one incorrectly.
A URL names a resource and says how to reach it. Take https://api.example.com:8443/v1/users?sort=name&page=2#top:
- scheme
https: the protocol.httpandhttpsare the web's; the scheme also implies a default port (80 for http, 443 for https). - host
api.example.com: a domain name (or an IP address) that DNS will resolve. - port
8443: optional; omitted when it's the default. - path
/v1/users: which resource on that server, hierarchical like folders. - query
?sort=name&page=2: key/value parameters, separated by&, typically for filtering, searching and pagination. - fragment
#top: a position inside the document. It's handled by the browser and never sent to the server.
Scheme plus host plus port make the origin (https://api.example.com:8443), the unit the browser's security model is built on.
URLs may only contain a limited set of ASCII characters, so everything else is percent-encoded: a space becomes %20, & inside a value becomes %26, and é becomes its UTF-8 bytes %C3%A9. In HTML form data and query strings a space is often written + instead. Never build query strings by concatenating raw user input; use a URL library (URL and URLSearchParams in JavaScript, urllib.parse in Python) that encodes correctly.
Relative URLs like ../img/a.png or /login are resolved against the current page's URL.
Example
const u = new URL("https://api.example.com:8443/v1/users?sort=name&page=2#top");
console.log(u.protocol, u.hostname, u.port); // https: api.example.com 8443
console.log(u.pathname, u.search, u.hash); // /v1/users ?sort=name&page=2 #top
console.log(u.origin); // https://api.example.com:8443
console.log(u.searchParams.get("page")); // 2
// Build query strings safely: values get encoded
const q = new URL("https://example.com/search");
q.searchParams.set("q", "fish & chips");
q.searchParams.set("city", "Zürich");
console.log(q.href);
// https://example.com/search?q=fish+%26+chips&city=Z%C3%BCrich
console.log(new URL("../img/a.png", "https://site.com/blog/post/").href);
// https://site.com/blog/img/a.pngRemember
- scheme://host:port/path?query#fragment
- Origin = scheme + host + port
- The fragment is never sent to the server
- Use a URL library to encode query values
Watch out for
- Concatenating user input into a query string, so a & or # in the value breaks the URL.