Vibe Engines
YouTube

Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path

HTTP Headers Quick Reference

The request and response headers that control caching, content, auth, CORS, and security — what each one does and sane values.

Headers are the metadata of every HTTP exchange: case-insensitive Name: value lines sent ahead of the body that tell the other side how to read it, cache it, secure it and route it. Request headers describe the client and what it wants; response headers describe the payload and the rules attached to it.

Many bugs that look like application bugs (stale pages, blocked fetches, lost cookies, wrong client IPs) are really one missing header or one wrong value. The fastest diagnosis is reading the raw headers with curl -v or the browser’s network panel.

Content & negotiation

Content-Type
Body’s media type: application/json, text/html; charset=utf-8
Accept
What the client wants back: Accept: application/json
Content-Encoding
gzip / br — compression applied to the body
Accept-Encoding
compressions the client can decode, e.g. gzip, br, zstd; the server picks one
Content-Disposition
attachment; filename="a.pdf" — force download
Content-Length
body size in bytes; absent when HTTP/1.1 streams with Transfer-Encoding: chunked
Vary
request headers that change the response, e.g. Vary: Accept-Encoding; caches key on them
Accept-Language
the user’s languages with weights: en-US,en;q=0.9

Caching

Cache-Control
max-age=3600 · no-store (never cache) · private / public
no-cache ≠ no-store
no-cache may store but must revalidate before reuse; only no-store forbids storing
Immutable assets
Cache-Control: public, max-age=31536000, immutable (hashed filenames)
s-maxage
a max-age for shared caches such as CDNs only; it overrides max-age there
stale-while-revalidate
serve a stale copy for that many seconds after expiry while refetching in the background
ETag / If-None-Match
Validator; server replies 304 Not Modified if unchanged
Last-Modified
Timestamp validator; paired with If-Modified-Since
Age
seconds the response sat in a cache — a nonzero value means a cache served it
Expires
legacy absolute expiry date, ignored when Cache-Control: max-age is present
CDN-Cache-Control
cache rules for CDNs only (RFC 9213), so browsers and CDNs can get different TTLs

Conditional & range requests

If-Match
optimistic concurrency: write only if the ETag still matches, else 412 Precondition Failed
Range
bytes=0-1023 asks for part of a resource; answered with 206 and Content-Range
Accept-Ranges
bytes means range requests work — resumable downloads, video seeking

Auth & cookies

Authorization
Bearer <token> · Basic <base64>
WWW-Authenticate
sent with 401 to name the auth scheme, e.g. Bearer realm="api"
Set-Cookie
Add HttpOnly; Secure; SameSite=Lax — the safe default
SameSite=None
needed for cross-site cookies (embeds, third-party SSO); rejected without Secure
__Host-session
name prefix: browsers enforce Secure, Path=/ and no Domain attribute
Max-Age=3600
cookie lifetime in seconds, winning over Expires; with neither it is a session cookie
Cookie
what the browser sends back: name=value pairs only, never the attributes

CORS (Access-Control-…)

Origin
scheme, host and port of the calling page; the server makes its CORS decision from it
…-Allow-Origin
CORS: which origins may read the response. Avoid blind * with credentials.
…-Allow-Methods
Allowed methods on the resource (preflight response)
…-Allow-Headers
request headers the real request may carry, e.g. Authorization, Content-Type
…-Allow-Credentials
true lets cookies through; then Allow-Origin must name the exact origin, never *
…-Expose-Headers
extra response headers JavaScript may read, such as X-Request-ID
…-Max-Age
seconds a browser may cache the preflight result; Chrome caps it at 2 hours
OPTIONS preflight
sent before non-simple requests, carrying Access-Control-Request-Method and -Headers

Security headers

Strict-Transport-Security
max-age=63072000; includeSubDomains — force HTTPS (HSTS)
HSTS preload
add preload and submit the domain to browsers’ list: HTTPS even on a first visit; hard to undo
Content-Security-Policy
allowlist where scripts, styles and frames may load from — the strongest defense against XSS
CSP Report-Only
Content-Security-Policy-Report-Only reports violations without blocking — roll out safely
X-Content-Type-Options
nosniff — stop MIME sniffing
X-Frame-Options
DENY — prevent clickjacking (or use CSP frame-ancestors)
Referrer-Policy
strict-origin-when-cross-origin — limit referrer leakage
Permissions-Policy
switch off browser features you don’t use: camera=(), geolocation=()
COOP
Cross-Origin-Opener-Policy set to same-origin cuts ties to cross-origin popups and openers
COEP · CORP
embedder and resource policies; with COOP they enable cross-origin isolation
X-XSS-Protection
obsolete — modern browsers ignore it; send 0 or omit it and rely on CSP

Proxies, tracing & APIs

Host
which site the request is for — required in HTTP/1.1, :authority in HTTP/2
X-Forwarded-For
client IP chain added by proxies; trust only entries your own proxies appended
X-Forwarded-Proto
the original scheme — how an app behind TLS termination knows the user used HTTPS
Forwarded
the standard form (RFC 7239): for=203.0.113.7;proto=https
Location
where to go next: the target of a 3xx redirect, or the new resource after 201
Retry-After
seconds (or a date) to wait, sent with 429 or 503; clients should honor it
X-Request-ID
a correlation ID echoed into every hop’s logs — quote it in bug reports
traceparent
W3C Trace Context: trace and parent span IDs that stitch distributed traces together
Idempotency-Key
client-chosen key so a retried POST takes effect once (Stripe-style APIs)
X-RateLimit-Remaining
a common convention for quota left; an IETF draft standardizes RateLimit headers
Server-Timing
backend timings shown in browser dev tools: db;dur=53, app;dur=47
Link
</items?page=2>; rel="next" for pagination, or rel=preload hints
Alt-Svc
advertises HTTP/3 on another protocol or port, e.g. h3=":443"

Recipes

Cache headers for a typical web app

# Hashed static assets (app.3f9a1c.js)
Cache-Control: public, max-age=31536000, immutable

# HTML pages: always revalidate, cheap 304s via the ETag
Cache-Control: no-cache
ETag: "v42"

# Personalized API responses
Cache-Control: no-store

Fingerprinted file names make year-long caching safe because new content gets a new URL; HTML must revalidate so users pick up the new asset links right after a deploy.

Check a site’s security headers from the terminal

curl -sI https://example.com | grep -iE 'strict-transport|content-security|x-content-type|x-frame|referrer-policy|permissions-policy'

-I fetches headers only and grep -i ignores case, since header names are case-insensitive. Any header missing from the output is one to add.

A correct CORS preflight exchange

OPTIONS /api/orders HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, authorization

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: content-type, authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 600
Vary: Origin

With credentials the server must echo the exact origin, never *, and Vary: Origin stops a cache serving one origin’s answer to another.

Revalidate instead of re-downloading

curl -sI https://example.com/data.json | grep -i etag
# etag: "abc123"
curl -s -o /dev/null -w '%{http_code}\n' -H 'If-None-Match: "abc123"' https://example.com/data.json
# 304

A 304 Not Modified has no body, so checking freshness costs one round trip instead of the whole payload.

A hardened session cookie

Set-Cookie: __Host-session=8f3a2c; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=86400

HttpOnly hides it from JavaScript, Secure keeps it on HTTPS, SameSite=Lax blocks most CSRF, and the __Host- prefix pins it to this exact host.

Questions about HTTP Headers Cheat Sheet

What is the difference between Cache-Control no-cache and no-store?

no-cache does not mean do not cache. It lets browsers and CDNs store the response but requires them to revalidate with the server before every reuse, typically with If-None-Match or If-Modified-Since, so an unchanged resource costs only a quick 304. no-store forbids storing the response anywhere, which is what you want for sensitive data such as account pages or one-time tokens. For HTML that changes with each deploy, no-cache plus an ETag gives fresh content cheaply; for hashed static assets, use a long max-age with immutable instead.

Why is my CORS request failing?

Start with the browser console and the preflight request. If the request uses a method other than GET, HEAD or POST, a custom header such as Authorization, or a JSON content type, the browser first sends an OPTIONS preflight, and the server must answer it with a 2xx status and the right Access-Control-Allow headers. Common causes are a server that returns 404 or 401 to OPTIONS, a missing Allow-Headers entry, or credentials sent while Allow-Origin is the wildcard. CORS is enforced by browsers only, so curl and server-to-server calls succeed regardless.

Which security headers should every website send?

A solid baseline is Strict-Transport-Security with a long max-age so browsers only use HTTPS; a Content-Security-Policy that restricts where scripts, styles and frames can load from, the strongest protection against cross-site scripting; X-Content-Type-Options set to nosniff; frame protection through CSP frame-ancestors or X-Frame-Options; a Referrer-Policy such as strict-origin-when-cross-origin; and a Permissions-Policy that disables features you do not use. X-XSS-Protection is obsolete and can be dropped. Roll out CSP in report-only mode first to see what it would break.

What is the difference between ETag and Last-Modified?

Both are validators that let a cache ask whether its copy is still current. Last-Modified is a timestamp with one-second resolution, checked with If-Modified-Since, so two changes within the same second, or a file whose timestamp changes without new content, can confuse it. An ETag is an opaque version identifier, often a content hash, checked with If-None-Match, and it is exact. A weak ETag, prefixed with W/, means equivalent rather than byte-identical. Servers often send both, and clients use the ETag when it is present.