1---2name: http3description: Use HTTP correctly with proper methods, status codes, headers, and caching.4---5
6## Redirects (Often Confused)
7
8- 307 vs 308: both preserve method; 307 temporary, 308 permanent—use these for POST/PUT redirects
9- 301/302 may change POST to GET (browser behavior)—don't use for API redirects with body
10- Include `Location` header with absolute URL—relative may fail in older clients
11- Redirect loops: limit to 5-10 follows; infinite loops crash clients
12
13## Caching Combinations
14
15- `Cache-Control: no-store` for sensitive data—never written to disk
16- `no-cache` still caches but revalidates every time—not "don't cache"
17- `private, max-age=0, must-revalidate` for user-specific, always-fresh content
18- `public, max-age=31536000, immutable` for versioned static assets
19- `Vary: Accept-Encoding, Authorization` when response depends on these headers—forgetting Vary breaks caching
20
21## Conditional Requests
22
23- `ETag` + `If-None-Match`: prefer for APIs—content hash based
24- Strong vs weak ETags: `"abc"` vs `W/"abc"`—weak allows semantically equivalent responses
25- `If-Match` for optimistic locking: fail update if resource changed since read
26- 412 Precondition Failed when `If-Match` fails—not 409 Conflict
27
28## CORS Preflight Triggers
29
30- Custom headers (anything not Accept, Accept-Language, Content-Language, Content-Type simple values)
31- Content-Type other than: application/x-www-form-urlencoded, multipart/form-data, text/plain
32- PUT, DELETE, PATCH methods—even to same origin if other conditions met
33- ReadableStream body—triggers preflight
34- Preflight cached per `Access-Control-Max-Age`—set to 86400 to reduce OPTIONS spam
35
36## Security Headers (Always Set)
37
38- `Strict-Transport-Security: max-age=31536000; includeSubDomains`—HSTS, once set can't easily undo
39- `X-Content-Type-Options: nosniff`—prevents MIME sniffing attacks
40- `X-Frame-Options: DENY` or `SAMEORIGIN`—prevents clickjacking
41- `Content-Security-Policy`—complex but essential; start with report-only mode
42
43## Range Requests
44
45- `Accept-Ranges: bytes` signals support—clients can request partial content
46- `Range: bytes=0-1023` requests first 1024 bytes; `bytes=-500` requests last 500
47- Return 206 Partial Content with `Content-Range: bytes 0-1023/5000`
48- 416 Range Not Satisfiable if range invalid—include `Content-Range: bytes */5000`
49
50## Error Response Best Practices
51
52- Structured JSON errors: `{"error": {"code": "VALIDATION_FAILED", "message": "...", "details": [...]}}`
53- Include request ID in error response—enables log correlation
54- Don't leak stack traces in production—log server-side, return generic message
55- 409 Conflict for business rule violations (duplicate email, insufficient funds)—not just 400
56
57## Retry Patterns
58
59- Retry only idempotent methods by default—GET, PUT, DELETE, HEAD
60- POST retry needs idempotency key—`Idempotency-Key: <client-generated-uuid>`
61- Exponential backoff: 1s, 2s, 4s, 8s... with jitter—prevents thundering herd
62- Respect `Retry-After` header—can be seconds or HTTP date
63- Set reasonable timeout (30s typical)—don't wait forever
64
65## Headers Often Forgotten
66
67- `Vary`: must include headers that affect response—CORS without `Vary: Origin` breaks
68- `Content-Disposition: attachment; filename="report.pdf"` for downloads
69- `X-Request-ID`: generate if not present, propagate to downstream services
70- `Accept-Language` for localized responses—respect with graceful fallback
71
72## Connection Behavior
73
74- HTTP/1.1 without `Content-Length` or chunked = connection close after response
75- `Transfer-Encoding: chunked` for streaming—can't set Content-Length
76- HTTP/2 is binary, multiplexed—no head-of-line blocking at HTTP level
77- WebSocket upgrade: GET with `Connection: Upgrade`, `Upgrade: websocket`