Getting Started
HTTP Request & Response
HTTP is a request-response protocol. Clients send requests (method, path, headers, optional body), servers respond with status, headers, and body. HTTP/1.1 is text-based, HTTP/2 and HTTP/3 use binary framing.
# HTTP Request
GET /api/users HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: application/json
# HTTP Response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 45
{"id": 1, "name": "Alice", "email": "[email protected]"}URL Structure
URLs identify resources. The scheme selects the protocol. The host is resolved via DNS. The default port is implied when omitted. The fragment (#) is client-side only and stripped before sending to the server. Query strings are commonly used for filtering/pagination.
# Generic URL format
scheme://userinfo@host:port/path?query#fragment
# Example
https://user:[email protected]:8443/api/v1/users?page=2#section
# Components
# scheme - https (protocol)
# userinfo - user:pass (rare, deprecated)
# host - example.com (domain or IP)
# port - 8443 (default: 80 for http, 443 for https)
# path - /api/v1/users (resource location)
# query - page=2 (key=value pairs, & separated)
# fragment - section (client-only, never sent to server)HTTP Versions Overview
HTTP/0.9 was a minimal prototype. HTTP/1.0 added headers and content types but opened a new connection per request. HTTP/1.1 introduced persistent connections, the mandatory Host header (enabling virtual hosts), and pipelining. HTTP/2 added binary multiplexing. HTTP/3 runs over QUIC, eliminating head-of-line blocking at the transport layer.
# HTTP/0.9 (1991) - single GET, no headers
GET /page.html
# HTTP/1.0 (1996) - headers, status codes, multiple types
GET /page.html HTTP/1.0
# HTTP/1.1 (1997) - persistent connections, Host header, pipelining
GET /page.html HTTP/1.1
Host: example.com
# HTTP/2 (2015) - binary, multiplexing, header compression
# (negotiated via ALPN or h2c upgrade)
# HTTP/3 (2022) - over QUIC (UDP-based)
# (negotiated via Alt-Svc header)Connection Lifecycle
HTTP/1.1 keeps TCP connections open by default (keep-alive), avoiding the cost of repeated handshakes. Multiple requests can be sent over one connection. The Connection: close header signals the last request. HTTP/2 multiplexes many streams over a single connection. Keep-Alive timeout and max are configurable on the server.
# HTTP/1.1 persistent connection (keep-alive)
GET /page1 HTTP/1.1
Host: example.com
Connection: keep-alive
# (server responds, connection stays open)
HTTP/1.1 200 OK
Content-Length: 128
Connection: keep-alive
# Client reuses same TCP connection for next request
GET /page2 HTTP/1.1
Host: example.com
# Closing the connection
GET /final HTTP/1.1
Host: example.com
Connection: closeMessage Format
HTTP messages start with a start-line (request-line or status-line), followed by headers, a blank line, and an optional body. Lines use CRLF line endings. Header names are case-insensitive. The blank line is mandatory and signals the start of the body. Bodies can be of any length (chunked) or fixed (Content-Length).
# Request format
<METHOD> <PATH> <VERSION>
<Header-Name>: <value>
...
<optional body>
# Response format
<VERSION> <STATUS> <REASON>
<Header-Name>: <value>
...
<optional body>
# Lines end with CRLF (
). Headers are case-insensitive.
# A blank line (
) separates headers from body.Telnet / Raw HTTP Debugging
You can speak HTTP raw over TCP using nc or telnet (port 80) or openssl s_client (HTTPS). This is invaluable for debugging. You must include the Host header on HTTP/1.1+. Two blank lines terminate the request. curl -v shows the wire-format conversation including headers.
# Manual HTTP request via netcat/nc
nc example.com 80
GET / HTTP/1.1
Host: example.com
# (press Enter twice to send blank line)
# Using openssl for HTTPS
openssl s_client -connect example.com:443
GET / HTTP/1.1
Host: example.com
# curl with --http1.1 to force version
curl -v --http1.1 https://example.com
curl -v --http2 https://example.com
curl -v --http3 https://example.comHTTP Methods
GET — Retrieve Resource
GET retrieves a representation of a resource. It must be safe (no side effects) and idempotent (repeatable). GET requests are cacheable and bookmarkable. Although the spec allows a body, it is discouraged — proxies and CDNs may strip it. Use query parameters for filtering instead.
# Basic GET
GET /api/users/42 HTTP/1.1
Host: api.example.com
Accept: application/json
# GET with query parameters
GET /api/users?role=admin&active=true HTTP/1.1
Host: api.example.com
# GET should be safe & idempotent
# - safe: no server state change
# - idempotent: repeating yields same result
# - cacheable: yes
# - body allowed but discouraged (some clients/servers reject)POST — Create Resource
POST submits data to be processed. It is used to create new resources where the server assigns the URI (e.g., /api/users → /api/users/43). POST is neither safe nor idempotent — submitting twice may create two resources. The 201 Created response should include a Location header pointing to the new resource.
# POST creating a new resource
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 52
{"name": "Bob", "email": "[email protected]", "age": 30}
# Response typically 201 Created with Location header
HTTP/1.1 201 Created
Location: /api/users/43
Content-Type: application/json
{"id": 43, "name": "Bob"}
# POST is neither safe nor idempotent.
# Repeating may create duplicate resources.PUT — Replace Resource
PUT replaces the entire resource at the target URI with the request body. It is idempotent — repeating the same PUT produces the same end state. PUT targets a specific URI (e.g., /users/43), unlike POST which targets a collection. If a field is omitted in PUT, it is typically removed (full replacement).
# PUT replaces the entire resource at the given URI
PUT /api/users/43 HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 60
{"id": 43, "name": "Robert", "email": "[email protected]", "age": 31}
# Idempotent: sending the same PUT again yields the same state.
# If the resource doesn't exist, PUT may create it (server-dependent).
# Response
HTTP/1.1 200 OK
# or 204 No Content if no body returnedPATCH — Partial Update
PATCH applies partial updates to a resource, unlike PUT which replaces it entirely. The simplest form is JSON Merge Patch (RFC 7396): send only the fields to change. JSON Patch (RFC 6902) uses an array of operations (add, remove, replace, move, copy, test). PATCH is NOT idempotent by default, though merge-patch is.
# PATCH applies partial modifications
PATCH /api/users/43 HTTP/1.1
Host: api.example.com
Content-Type: application/merge-patch+json
Content-Length: 22
{"email": "[email protected]"}
# Only the email field is updated; other fields remain.
# JSON Patch (RFC 6902) - structured operations
PATCH /api/users/43 HTTP/1.1
Content-Type: application/json-patch+json
[
{"op": "replace", "path": "/email", "value": "[email protected]"},
{"op": "remove", "path": "/age"}
]DELETE — Remove Resource
DELETE removes the target resource. It is idempotent — deleting the same resource twice should leave the server in the same state. Common success codes are 204 (no body), 200 (with body confirming), or 202 (async deletion). Most APIs require authentication. Whether to return 404 on a missing resource is debated — 204 is safer for idempotency.
# Delete a resource
DELETE /api/users/43 HTTP/1.1
Host: api.example.com
Authorization: Bearer <token>
# Successful responses:
HTTP/1.1 204 No Content # most common
HTTP/1.1 200 OK # if body returned
HTTP/1.1 202 Accepted # async deletion queued
# Idempotent: deleting an already-deleted resource
# should still return 204 (or 404 — debatable).HEAD & OPTIONS
HEAD is identical to GET but the server returns only headers (no body) — useful for checking Content-Length, Content-Type, or Last-Modified without downloading the body. OPTIONS asks which methods are allowed (Allow header) and is used by browsers for CORS preflight. Both are safe and idempotent.
# HEAD: like GET but returns headers only (no body)
HEAD /api/users/42 HTTP/1.1
Host: api.example.com
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 128
# (no body)
# OPTIONS: describe communication options
OPTIONS /api/users HTTP/1.1
Host: api.example.com
HTTP/1.1 200 OK
Allow: GET, POST, HEAD, OPTIONS
Access-Control-Allow-Methods: GET, POSTStatus Codes
1xx Informational
1xx codes are informational, indicating the request was received and processing continues. 100 Continue lets a client check whether to send a large body (paired with the Expect: 100-continue header). 101 Switching Protocols enables WebSocket. 103 Early Hints lets the server hint the browser to preload assets before the final response is ready.
# 100 Continue - server received headers, client may send body
POST /upload HTTP/1.1
Host: example.com
Expect: 100-continue
Content-Length: 1048576
# Server replies:
HTTP/1.1 100 Continue
# (client now sends the request body)
# 101 Switching Protocols - used for WebSocket upgrade
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
# 103 Early Hints - preload resources before final response
HTTP/1.1 103 Early Hints
Link: </style.css>; rel=preload; as=style2xx Success
2xx codes indicate success. 200 OK is the generic success. 201 Created indicates a new resource was made (with a Location header). 202 Accepted means the request is queued for async processing (e.g., a long job). 204 No Content signals success without a body — common for DELETE/PUT. 206 Partial Content returns part of a resource (Range request).
# 200 OK - standard success
HTTP/1.1 200 OK
# 201 Created - new resource created (POST/PUT)
HTTP/1.1 201 Created
Location: /api/users/43
# 202 Accepted - request queued for async processing
HTTP/1.1 202 Accepted
# 204 No Content - success, no body (DELETE, PUT)
HTTP/1.1 204 No Content
# 206 Partial Content - Range request result
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/20483xx Redirection
3xx codes indicate redirection. 301/308 are permanent (cacheable, SEO link juice passes); 302/307 are temporary. The crucial difference: 301 and 302 historically allowed POST→GET conversion (causing data loss), while 307 and 308 strictly preserve the method. 304 Not Modified is returned on conditional requests when the cache is valid — no body sent.
# 301 Moved Permanently - cacheable, change bookmarks
HTTP/1.1 301 Moved Permanently
Location: https://newsite.com/page
# 302 Found - temporary redirect (don't update bookmarks)
HTTP/1.1 302 Found
Location: /login
# 304 Not Modified - cache is still valid (conditional GET)
HTTP/1.1 304 Not Modified
ETag: "abc123"
# 307 Temporary Redirect - preserves method (POST stays POST)
HTTP/1.1 307 Temporary Redirect
Location: /new-endpoint
# 308 Permanent Redirect - permanent, preserves method
HTTP/1.1 308 Permanent Redirect
Location: https://newsite.com/api4xx Client Errors
4xx codes mean the client made an error. 400 Bad Request is malformed input. 401 means no/invalid authentication (must include WWW-Authenticate). 403 means authenticated but lacking permission. 404 is a missing resource. 429 indicates rate limiting (include Retry-After). Other common ones: 405 Method Not Allowed, 409 Conflict, 422 Unprocessable Entity.
# 400 Bad Request - malformed syntax
HTTP/1.1 400 Bad Request
Content-Type: application/json
{"error": "Invalid JSON in request body"}
# 401 Unauthorized - authentication required
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
# 403 Forbidden - authenticated but not allowed
HTTP/1.1 403 Forbidden
# 404 Not Found - resource doesn't exist
HTTP/1.1 404 Not Found
# 429 Too Many Requests - rate limit hit
HTTP/1.1 429 Too Many Requests
Retry-After: 605xx Server Errors
5xx codes mean the server failed. 500 is a catch-all for unhandled errors (check server logs). 501 means the server doesn't implement the method. 502 means a proxy/gateway got a bad response from upstream. 503 means temporary overload (use Retry-After). 504 means an upstream timeout. Clients may retry 502/503/504 with backoff.
# 500 Internal Server Error - generic server failure
HTTP/1.1 500 Internal Server Error
# 501 Not Implemented - server doesn't support the method
HTTP/1.1 501 Not Implemented
# 502 Bad Gateway - upstream server returned invalid response
HTTP/1.1 502 Bad Gateway
# 503 Service Unavailable - temporary overload or maintenance
HTTP/1.1 503 Service Unavailable
Retry-After: 300
# 504 Gateway Timeout - upstream didn't respond in time
HTTP/1.1 504 Gateway TimeoutStatus Code Patterns
A consistent status code mapping makes APIs predictable. Use 2xx for success with semantic precision (201 for create, 204 for no body). 4xx for client errors with the most specific code (409 for conflicts, 422 for validation). 401 vs 403 is the most common confusion: 401 = 'who are you?', 403 = 'I know who you are, but you can't do this'.
# REST API common mapping
GET /users -> 200
POST /users -> 201 (Created)
GET /users/42 -> 200 | 404
PUT /users/42 -> 200 | 201 (if created) | 404
PATCH /users/42 -> 200 | 404
DELETE /users/42 -> 204 | 404
# Validation errors
400 -> malformed JSON, missing required field
409 -> duplicate resource / version conflict
422 -> semantic validation failure (some APIs)
# Auth flow
401 -> no/invalid token (login required)
403 -> logged in but lacking permission
404 -> hide existence from unauthorized users
# Use 418 I'm a teapot for fun (RFC 2324 joke).Request Headers
Common Request Headers
Common request headers convey client identity (User-Agent), desired response format (Accept family), connection control (Connection), authentication (Authorization), state (Cookie), and origin (Referer/Origin). Host is mandatory in HTTP/1.1+ for virtual hosting. Content-Type and Content-Length describe any request body.
GET /api/data HTTP/1.1
Host: api.example.com # target host (mandatory in HTTP/1.1)
User-Agent: Mozilla/5.0 # client identity
Accept: application/json # desired response format
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Authorization: Bearer <token>
Cookie: session=abc123; theme=dark
Referer: https://example.com/
Origin: https://example.com
Content-Type: application/json
Content-Length: 42Accept Headers (Content Negotiation)
The Accept family drives content negotiation. Quality values (q, 0-1) express preference — higher is more preferred. */* is a wildcard catch-all. The server picks the best match from what it supports; if none match, it returns 406 Not Acceptable (though most servers fall back to a default rather than 406). Brotli (br) and zstd offer better compression than gzip.
# Accept: desired media types with quality (q) values
Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
# Accept-Language: preferred languages
Accept-Language: en-US,en;q=0.9, zh-CN;q=0.8, fr;q=0.7
# Accept-Encoding: accepted compression algorithms
Accept-Encoding: gzip, deflate, br, zstd;q=0.9
# q=1.0 is default. Higher q = more preferred.
# */* matches any type.
# Server responds with 406 Not Acceptable if it can't satisfy.Authorization & Auth Headers
Authorization carries credentials. Basic auth sends base64-encoded username:password on every request (always use HTTPS). Bearer tokens are opaque strings (often JWTs) used in OAuth 2.0. Custom auth schemes (X-API-Key) are common for API gateways. Basic auth's base64 is encoding, not encryption — it offers no security without TLS.
# Basic Authentication (base64 of user:pass)
Authorization: Basic dXNlcjpwYXNz
# dXNlcjpwYXNz = base64("user:pass")
# Bearer Token (OAuth 2.0 / JWT)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
# API Key in header (custom)
X-API-Key: abc123def456
# Proxy authentication
Proxy-Authorization: Basic dXNlcjpwYXNz
# WARNING: Basic auth sends credentials on every request.
# Always use HTTPS to prevent eavesdropping.User-Agent & Referer
User-Agent identifies the client, but most browsers fake Mozilla/5.0 for backward compatibility (historical sniffing). Referer (misspelled in the spec, never corrected) tells the server which page linked to the request — used for analytics and hotlink protection. Origin is the scheme+host+port, sent by browsers on CORS requests and POSTs.
# User-Agent identifies the client software
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
# Common browsers prepend "Mozilla/5.0" for historical compatibility
# (servers used to serve different content to different browsers)
# Referer: page that linked to this request
Referer: https://example.com/search?q=hello
# Origin: scheme + host + port (used by CORS)
Origin: https://example.com
# Note: "Referer" is the official spelling (misspelled in the original spec)Conditional Request Headers
Conditional headers enable efficient caching and concurrency control. If-None-Match (with ETag) and If-Modified-Since (with Last-Modified) make GET conditional — server returns 304 if the cache is valid. If-Match and If-Unmodified-Since guard PUT/PATCH against lost updates (optimistic concurrency). If-Range enables atomic range requests.
# Conditional GET - only fetch if changed
If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT
If-None-Match: "abc123"
# If-Match / If-Unmodified-Since - for safe PUT/PATCH
If-Match: "abc123"
If-Unmodified-Since: Wed, 21 Oct 2023 07:28:00 GMT
# If-Range - for range requests (all-or-nothing)
If-Range: "abc123"
Range: bytes=0-1023
# Typical flow:
# 1. Server sends ETag/Last-Modified with response
# 2. Client sends If-None-Match/If-Modified-Since on next request
# 3. Server replies 304 if unchanged, 200 if changedCustom & X-Headers
Custom headers historically used the X- prefix, but RFC 6648 deprecated this convention in 2012. New headers should drop X- (e.g., Request-ID not X-Request-ID). X-Forwarded-For and X-Forwarded-Proto carry client info through proxies (note: spoofable). The standardized alternative is Forwarded (RFC 7239). Traceparent/Tracestate enable distributed tracing (W3C).
# X- prefixed headers (deprecated convention, but widely used)
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
X-Correlation-ID: abc-123
X-Forwarded-For: 203.0.113.1, 70.41.3.18
X-Forwarded-Proto: https
X-Real-IP: 203.0.113.1
X-RateLimit-Remaining: 42
# Modern recommendation: avoid X- prefix (RFC 6648)
# Use a namespace instead:
Request-ID: 550e8400-e29b-41d4-a716-446655440000
Traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01
# Forwarded (RFC 7239) - standardized proxy info
Forwarded: for=203.0.113.1; proto=https; host=example.comResponse Headers
Common Response Headers
Common response headers describe the server (Server), the response body (Content-Type, Content-Length), connection control (Connection), caching (Cache-Control, ETag, Last-Modified), content negotiation (Vary), state (Set-Cookie), and CORS (Access-Control-*). Date is mandatory and uses the RFC 1123 format in GMT.
HTTP/1.1 200 OK
Server: nginx/1.25.0
Date: Wed, 21 Oct 2023 07:28:00 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 128
Connection: keep-alive
Cache-Control: public, max-age=3600
ETag: "abc123"
Last-Modified: Mon, 20 Oct 2023 10:00:00 GMT
Vary: Accept-Encoding
Set-Cookie: session=xyz; HttpOnly; Secure
Access-Control-Allow-Origin: https://example.comContent Headers
Content-* headers describe the body. Content-Type is the MIME type and is critical. Content-Length gives the exact byte count (required unless using chunked encoding). Content-Encoding indicates compression (gzip, br). Content-Disposition forces download with a filename. Content-Range accompanies 206 Partial Content responses.
# Body metadata
Content-Type: application/json; charset=utf-8
Content-Length: 128 # exact byte count
Content-Encoding: gzip # applied encoding
Content-Language: en-US
Content-Location: /api/users/42.json
Content-Disposition: attachment; filename="report.pdf"
Content-Range: bytes 0-1023/2048 # for partial content
# For chunked transfer (no Content-Length known upfront)
Transfer-Encoding: chunked
# MIME type format: type/subtype; parameter=value
# e.g., text/html; charset=UTF-8Security Headers
Security headers harden browsers against common attacks. HSTS forces HTTPS and prevents SSL stripping. X-Content-Type-Options: nosniff prevents MIME sniffing. X-Frame-Options (or CSP frame-ancestors) blocks clickjacking. CSP is the most powerful — it controls which resources can load and execute. Referrer-Policy limits leaked referrer info. Set these on every response.
# Force HTTPS for 6 months (incl. subdomains)
Strict-Transport-Security: max-age=15768000; includeSubDomains; preload
# Prevent MIME-type sniffing
X-Content-Type-Options: nosniff
# Prevent clickjacking
X-Frame-Options: DENY
# Or modern CSP frame-ancestors:
Content-Security-Policy: frame-ancestors 'none'
# Referrer policy
Referrer-Policy: strict-origin-when-cross-origin
# Permissions policy (feature lockdown)
Permissions-Policy: geolocation=(), camera=()
# Full Content-Security-Policy
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.comCORS Response Headers
CORS (Cross-Origin Resource Sharing) headers let a server opt-in to cross-origin requests. Access-Control-Allow-Origin is required for any cross-origin read; either a specific origin or *. If credentials are involved, Allow-Credentials: true AND a specific origin (no wildcard). Preflight (OPTIONS) responses include Allow-Methods/Headers. Expose-Headers lets JS read non-default response headers.
# Allow a specific origin
Access-Control-Allow-Origin: https://example.com
# Or wildcard (but credentials won't work with *)
Access-Control-Allow-Origin: *
# Allow credentials (cookies, Authorization)
Access-Control-Allow-Credentials: true
# Allowed methods (preflight response)
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
# Allowed headers (preflight response)
Access-Control-Allow-Headers: Content-Type, Authorization
# How long browser can cache preflight (seconds)
Access-Control-Max-Age: 86400
# Headers the JS can read from the response
Access-Control-Expose-Headers: X-Request-ID, X-Total-CountCache Headers
Cache-Control is the modern (HTTP/1.1) caching header with directives: public/private (who may cache), max-age (freshness in seconds), no-cache (must revalidate), no-store (never cache), immutable (URL never changes). ETag and Last-Modified are validators used with conditional requests. Expires (HTTP/1.0) is a fallback. Age tells how long a response has been cached.
# Cache-Control directives (HTTP/1.1 - preferred)
Cache-Control: public, max-age=3600
Cache-Control: private, max-age=600
Cache-Control: no-cache # revalidate before use
Cache-Control: no-store # never cache
Cache-Control: must-revalidate
Cache-Control: immutable
# Validators
ETag: "abc123" # opaque version tag
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT
# HTTP/1.0 fallbacks (deprecated)
Expires: Wed, 21 Oct 2023 08:28:00 GMT
Pragma: no-cache
# Age: time a response has been in a cache (seconds)
Age: 120