Updated 10 hours ago
When you request something from a server, the response comes in two parts. The body is what you asked for—the HTML, the image, the JSON data. The headers are the server telling you what it just handed you and what you should do with it.
Think of it like receiving a package. The package contents are the body. The headers are the handling instructions attached to the outside: "Fragile." "Refrigerate after opening." "This is a gift—don't show the price."
The Questions Every Response Answers
Every HTTP response implicitly answers a set of questions:
What is this? The Content-Type header tells the browser whether it's looking at HTML, JSON, an image, or a PDF. Without it, the browser receives a stream of bytes with no idea how to interpret them.
How big is it? Content-Length lets browsers show download progress and know when they've received everything.
Is it compressed? Content-Encoding tells browsers to decompress the response before using it.
Can I cache it? Cache-Control and related headers determine whether browsers and CDNs can store copies, and for how long.
What security rules apply? Headers like Content-Security-Policy and Strict-Transport-Security tell browsers what to block and what to enforce.
Should I store any cookies? Set-Cookie headers create persistent state between requests.
Should I go somewhere else? Location headers (with redirect status codes) tell browsers to request a different URL.
Every response header is an answer to one of these questions.
Content Headers: What You're Getting
Content-Type
The most fundamental response header. It tells the browser how to interpret the bytes it just received:
Without Content-Type, the browser receives a stream of bytes and has no idea what it's looking at. Is this HTML to render? JSON to parse? An image to display? The bytes themselves don't say.
Common values:
text/html— render as a webpageapplication/json— parse as structured dataimage/png— display as an imageapplication/pdf— display or download as PDFtext/css— apply as stylesheetapplication/javascript— execute as code
The charset=utf-8 part specifies character encoding. Get this wrong and text displays as garbled nonsense.
Content-Length
The size of the response body in bytes:
This header enables progress bars. Without knowing the total size, browsers can only show "loading..." with no indication of how much remains. It also lets clients verify they received the complete response.
Content-Encoding
Indicates compression applied to the response:
The browser automatically decompresses before processing. Common encodings:
gzip— widely supported, good compressionbr— Brotli, better compression ratios for text
Compression can reduce transfer size by 70-90% for text content like HTML, CSS, and JavaScript. The bytes on the wire are compressed; the browser inflates them back to the original.
Content-Disposition
Controls whether content displays inline or triggers a download:
With inline (the default for most content), browsers display the response directly. With attachment, they prompt the user to save a file. The filename parameter suggests what to call it.
This is how a server can send identical bytes but have one URL display a PDF in-browser while another triggers a download dialog.
Caching Headers: Can I Keep a Copy?
Cache-Control
The primary header controlling how responses can be cached:
The directives that matter:
public — any cache can store this: CDNs, proxies, browsers. Use for static assets like images and scripts.
private — only the user's browser can cache this, not shared caches. Use for personalized content.
max-age=3600 — the response is fresh for 3600 seconds (one hour). During this window, caches can serve it without checking with the server.
no-cache — caches must validate with the server before using a stored copy. The cache keeps the response but always checks if it's still valid.
no-store — don't cache at all. The response should never be written to disk. Use for sensitive data.
must-revalidate — once stale, caches must revalidate. They cannot serve stale content even if the server is unreachable.
ETag
A fingerprint that uniquely identifies a specific version of the resource:
Here's how ETags make caching efficient: The browser caches the response along with its ETag. Later, when the cache entry is stale, the browser requests the resource again but includes the ETag in an If-None-Match header. If the content hasn't changed, the server responds with 304 Not Modified—no body, just confirmation that the cached version is still valid.
This turns a potentially large download into a tiny validation check.
Last-Modified
When the resource was last changed:
Similar to ETag but based on timestamps rather than content fingerprints. The browser sends this back in If-Modified-Since headers for validation. Less precise than ETags (only one-second granularity) but simpler to implement.
Cookie Headers: Remember This
Set-Cookie
Instructs the browser to store a cookie:
The cookie value (sessionId=abc123) is the data. The attributes control behavior:
Secure — only send this cookie over HTTPS. Prevents interception on insecure connections.
HttpOnly — JavaScript cannot access this cookie. Protects session tokens from XSS attacks that try to steal cookies via document.cookie.
SameSite — controls when cookies are sent with cross-site requests:
Strict— never send cross-site (strongest protection)Lax— send on top-level navigations but not embedded requestsNone— always send (requires Secure; used for legitimate cross-site scenarios)
Max-Age — how many seconds until the cookie expires. Without this or Expires, the cookie is a "session cookie" that disappears when the browser closes.
A single response can include multiple Set-Cookie headers to set multiple cookies.
Security Headers: Enforce These Rules
Strict-Transport-Security (HSTS)
Tells browsers to always use HTTPS:
Once a browser receives this header, it automatically converts any HTTP request to HTTPS for the specified duration. Even if a user types http:// or clicks an HTTP link, the browser upgrades to HTTPS before sending anything.
This prevents attackers from intercepting the initial HTTP request before a redirect to HTTPS could happen.
Content-Security-Policy (CSP)
Defines which resources the page is allowed to load:
CSP creates a whitelist. Any resource not explicitly allowed gets blocked. This is powerful protection against XSS attacks—even if an attacker injects a malicious script tag, it won't execute if the source isn't whitelisted.
The directives specify source rules for different resource types: script-src for JavaScript, img-src for images, style-src for CSS, and so on. default-src sets the fallback for anything not explicitly specified.
X-Content-Type-Options
Prevents browsers from "sniffing" the content type. Without this, browsers might ignore the Content-Type header and guess based on the content itself. If user-uploaded content gets misinterpreted as executable JavaScript, that's a security hole. This header forces browsers to trust Content-Type.
X-Frame-Options
Controls whether the page can be embedded in a frame:
DENY— cannot be framed by anyoneSAMEORIGIN— can only be framed by pages from the same origin
This prevents clickjacking attacks where a malicious site embeds your page in an invisible iframe and tricks users into clicking on it.
CORS Headers: Cross-Origin Access
When JavaScript on one origin tries to access a resource from a different origin, browsers block it by default. CORS headers grant explicit permission.
Access-Control-Allow-Origin
The fundamental CORS header:
This says: "JavaScript from https://www.example.com is allowed to read this response." Without this header, the browser fetches the response but refuses to let JavaScript access it.
The wildcard * allows any origin, but cannot be used with credentials (cookies).
Access-Control-Allow-Methods
Which HTTP methods are allowed for cross-origin requests:
This appears in responses to preflight requests, telling browsers which methods the actual request can use.
Access-Control-Allow-Headers
Which request headers are permitted:
Custom headers require explicit permission. Without this, browsers reject cross-origin requests that include headers beyond the basic safe list.
Access-Control-Max-Age
How long browsers can cache preflight results:
Preflight requests add latency. Caching the results for 86400 seconds (one day) means browsers don't need to preflight every single cross-origin request.
Redirect Headers
Location
Used with 3xx status codes to specify where to go:
When a response has a redirect status code (301, 302, 307, 308), the browser automatically requests the URL in the Location header. The redirect status code determines whether the browser can cache the redirect and whether it should change the HTTP method.
Connection Headers
Transfer-Encoding
How the message body is transferred:
Chunked encoding allows servers to start sending before knowing the total content length. Each chunk arrives with its size, and a zero-size chunk signals the end. This enables streaming responses and dynamically generated content where the final size isn't known upfront.
With chunked encoding, there's no Content-Length header—the chunks themselves define the boundaries.
Server Information
Date
When the response was generated:
Useful for debugging and calculating cache freshness.
Age
How long the response has been sitting in a cache:
CDNs and proxies add this header. If Cache-Control says max-age=7200 and Age says 3600, the response has one hour of freshness remaining.
Server
Identifies the server software:
Informational, but often omitted in production because revealing exact versions helps attackers target known vulnerabilities.
Frequently Asked Questions About Response Headers
Was this page helpful?