A URL is the address of a web resource, but it's really a structure of well-defined parts assembled in a fixed order. Its grammar is set by RFC 3986, and understanding it precisely clarifies most routing, encoding, and security issues. First, the terms: a URI is the broader concept that identifies a resource, and a URL is the kind that also tells you its location. In everyday use the two are treated as synonyms.
The five components
RFC 3986's generic syntax is scheme://authority/path?query#fragment. Let's map each part onto an example.
https://user:pass@api.example.com:8443/v1/items?sort=asc&page=2#section-3
\___/ \_______/ \_____________/ \__/ \_______/ \_____________/ \_______/
scheme userinfo host port path query fragment
\__________________________/
authority
- scheme (
https): the protocol and interpretation rules; followed by:. - authority: of the form
userinfo@host:port. host is a domain or IP; port defaults to the scheme's default (http=80, https=443) when omitted; userinfo (user:pass) should not be placed in URLs for security reasons. - path (
/v1/items): the hierarchical resource path. - query (
sort=asc&page=2): key=value pairs after?, separated by&by convention. - fragment (
#section-3): a location within the document. It is never sent to the server — it's client-side only.
Percent-encoding and character sets
You can't put arbitrary characters in a URL. RFC 3986 splits characters into two groups. Unreserved characters (A-Z a-z 0-9 - . _ ~) may appear literally anywhere. Reserved characters (: / ? # [ ] @ ! $ & ' ( ) * + , ; =) carry special meaning as delimiters, so to include one as data you must percent-encode it. A space becomes %20, & becomes %26, and the Korean syllable '한' becomes %ED%95%9C (its UTF-8 bytes encoded).
The key point is that encoding rules depend on context. The same / is left alone as a path separator, but to place it as data inside a query value you must encode it as %2F. That's why browsers and standard libraries provide separate encoders for 'a path segment' versus 'a query component.' Using the wrong one causes bugs where + (which can mean a space in a query) or / is misinterpreted.
IDN and punycode
Using non-ASCII characters (Korean, Chinese, emoji, etc.) in a domain is an Internationalized Domain Name (IDN). Since DNS traditionally handles only ASCII, a Unicode domain is converted to an ASCII form via punycode, and the converted label gets an xn-- prefix. For example, the Korean label of 한국.example encodes to something like xn--3e0b707e. Because of homograph attacks — mixing visually similar characters to forge a domain — browsers sometimes show punycode instead of Unicode in the address bar.
Relative vs absolute, and normalization
An absolute URL is a complete address with a scheme and everything, while a relative URL (../images/logo.png, ?page=2) is interpreted against the current document's base URL. Browsers resolve relative to absolute using RFC 3986's reference-resolution rules.
- Normalization: URLs that look different can point to the same resource. Scheme and host are case-insensitive (
HTTP≡http), default ports (:80,:443) equal omission,%41decodes toA, and/a/./b/../csimplifies to/a/c. - Caution: path case and the query string can be significant depending on the server, so don't normalize them blindly.
- Security: mishandling
../becomes a path-traversal vulnerability, and confusing the order of normalization can let access control be bypassed — so be especially careful at trust boundaries.