HTTP Response Headers Explained

Complete guide — caching, security, CORS, cookies, and 30+ response headers with examples

HTTP & APIsJune 26, 202618 min readBy Keyur Patel

Every HTTP response from a server includes headers — metadata that tells the browser how to handle the response. These headers control caching (saving bandwidth), security (preventing attacks), content delivery (format and encoding), cookies (maintaining state), and cross-origin access (CORS). Understanding response headers is essential for building fast, secure, and reliable web applications.

This guide covers 30+ HTTP response headers organized by category, with practical examples showing exactly when and how to use each one.

Anatomy of an HTTP Response

Every HTTP response has three parts: status line, headers, and body:

HTTP/1.1 200 OK                          ← Status line
Content-Type: application/json            ← Response headers
Cache-Control: max-age=3600               ←
Set-Cookie: session=abc123; HttpOnly      ←
X-Content-Type-Options: nosniff           ←
                                          ← Blank line (separates headers from body)
{"id": 1, "name": "Alice"}               ← Response body

Response Header Categories

CategoryHeadersPurpose
ContentContent-Type, Content-Length, Content-Encoding, Content-DispositionDescribe what the response body contains and how to handle it
CachingCache-Control, ETag, Last-Modified, Expires, VaryControl how long browsers and CDNs store the response
SecurityCSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-PolicyProtect against XSS, clickjacking, and other attacks
CORSAccess-Control-Allow-Origin, Allow-Methods, Allow-Headers, Allow-CredentialsControl which domains can access the API from browsers
CookiesSet-CookieStore data on the client (sessions, preferences, auth)
RedirectsLocationTell the client to navigate to a different URL
ConnectionConnection, Transfer-Encoding, Keep-AliveManage the TCP connection lifecycle
Server InfoServer, Date, X-Powered-ByServer identification (consider hiding for security)

Caching Headers Explained

Caching headers are the single most impactful performance optimization you can make. They tell browsers and CDNs to reuse previous responses instead of downloading them again.

Cache-Control

The most important caching header. Controls who can cache, for how long, and under what conditions.

Cache-Control: public, max-age=31536000    → CDN + browser cache for 1 year (static assets)
Cache-Control: private, max-age=3600       → Browser only, 1 hour (user-specific data)
Cache-Control: no-cache                    → Must revalidate with server before using cache
Cache-Control: no-store                    → Never cache (sensitive data, banking pages)
Cache-Control: must-revalidate, max-age=0  → Always check with server

ETag + If-None-Match

A content fingerprint. Server sends ETag with response; browser sends it back with If-None-Match on next request. If content hasn't changed, server returns 304 (no body) — saving bandwidth.

// First response:
ETag: "abc123hash"
// Next request from browser:
If-None-Match: "abc123hash"
// Server response if unchanged:
304 Not Modified (no body sent — browser uses cached version)

Vary

Tells caches that the response varies based on specific request headers. Without Vary, a cached gzipped response might be served to a client that doesn't support gzip.

Vary: Accept-Encoding    → Cache separate versions for gzip vs non-gzip
Vary: Accept-Language    → Cache separate versions per language
Vary: Authorization      → Don't serve one user's cached response to another

Security Headers Explained

Security headers are your server-side defense layer. They instruct browsers to enforce security policies that prevent common web attacks. Every production site should set these:

Strict-Transport-Security (HSTS)

Strict-Transport-Security: max-age=31536000; includeSubDomains

Forces HTTPS for the entire domain. Prevents SSL stripping attacks. Browser remembers to always use HTTPS even if user types http://.

🛡️ Prevents: Man-in-the-middle, SSL downgrade

Content-Security-Policy (CSP)

Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com

Controls what resources can load on the page. Blocks inline scripts, unauthorized domains, and injected content.

🛡️ Prevents: XSS (Cross-Site Scripting)

X-Frame-Options

X-Frame-Options: DENY

Prevents your page from being embedded in an iframe on another site. Stops attackers from overlaying invisible iframes to steal clicks.

🛡️ Prevents: Clickjacking

X-Content-Type-Options

X-Content-Type-Options: nosniff

Prevents browsers from guessing (sniffing) the content type. A JavaScript file served as text/plain won't be executed.

🛡️ Prevents: MIME type confusion attacks

Referrer-Policy

Referrer-Policy: strict-origin-when-cross-origin

Controls how much URL information is sent in the Referer header when navigating to other sites. Prevents leaking sensitive URL paths.

🛡️ Prevents: Information leakage via Referer

Permissions-Policy

Permissions-Policy: camera=(), microphone=(), geolocation=()

Controls which browser features (camera, mic, location) your page and embedded iframes can access. Blocks third-party scripts from using sensitive APIs.

🛡️ Prevents: Unauthorized device access by embedded content

CORS Response Headers

CORS headers tell browsers which cross-origin requests to allow. Without them, JavaScript on one domain cannot read responses from a different domain:

// Server response headers for CORS:
Access-Control-Allow-Origin: https://myapp.com       → Only this origin allowed
Access-Control-Allow-Methods: GET, POST, PUT, DELETE → Allowed HTTP methods
Access-Control-Allow-Headers: Authorization, Content-Type → Allowed request headers
Access-Control-Allow-Credentials: true               → Allow cookies cross-origin
Access-Control-Max-Age: 86400                        → Cache preflight for 24 hours
Access-Control-Expose-Headers: X-Total-Count         → Headers JS can read

// ⚠️ Common mistake:
Access-Control-Allow-Origin: *    → Allows ANY domain (never use with credentials)

// ✅ Correct for authenticated APIs:
Access-Control-Allow-Origin: https://myapp.com  → Specific origin only

Content and Cookie Headers

Content-Type

Tells the browser what format the response body is in. The browser uses this to decide how to render or parse the response. Wrong Content-Type = broken rendering.

Content-Type: text/html; charset=utf-8           → HTML page
Content-Type: application/json                    → JSON API response
Content-Type: image/png                           → PNG image
Content-Type: application/pdf                     → PDF document
Content-Type: application/octet-stream            → Binary file download
Content-Type: text/css                            → CSS stylesheet
Content-Type: application/javascript              → JavaScript file

Set-Cookie

Instructs the browser to store a cookie that will be sent back with future requests:

// Secure session cookie (recommended)
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=86400

// Flags explained:
// HttpOnly  → JavaScript cannot read this cookie (XSS protection)
// Secure    → Only sent over HTTPS
// SameSite=Strict → Not sent with cross-origin requests (CSRF protection)
// Path=/    → Cookie valid for all paths
// Max-Age   → Expires after 24 hours (in seconds)

// ❌ Insecure cookie (never do this in production):
Set-Cookie: token=secret123
// Missing HttpOnly, Secure, SameSite — vulnerable to XSS, CSRF, and interception

Content-Disposition

Controls whether the browser displays the response inline or triggers a download:

Content-Disposition: inline                          → Display in browser (default)
Content-Disposition: attachment; filename="report.pdf" → Trigger download with filename

Location (Redirects)

Used with 3xx status codes to tell the client where to go next:

HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/new-page

HTTP/1.1 302 Found
Location: /dashboard    → Temporary redirect (e.g., after login)

How to View Response Headers

Chrome/Edge DevToolsF12 → Network tab → click any request → Headers tab → Response Headers section
Firefox DevToolsF12 → Network tab → click request → Headers tab (shows raw and parsed)
cURL (terminal)curl -I https://example.com (headers only) or curl -v (full verbose output)
PostmanSend request → click 'Headers' tab in the response panel
VS Code REST ClientSend request → response shows headers above the body

Common Developer Mistakes

⚠️ Missing Content-Type on API responses

Without Content-Type: application/json, browsers may not parse the response correctly. Frameworks like Express set this automatically, but raw Node.js does not.

⚠️ No Cache-Control on static assets

Without caching headers, browsers re-download CSS, JS, and images on every page load. Set max-age=31536000 for hashed static files.

⚠️ Missing security headers in production

No HSTS, no CSP, no X-Frame-Options = vulnerable to HTTPS downgrade, XSS, and clickjacking. Use securityheaders.com to audit your site.

⚠️ Using Access-Control-Allow-Origin: * with credentials

Browsers reject this combination. If you need credentials (cookies), specify the exact origin instead of wildcard.

⚠️ Exposing the Server header

Server: Apache/2.4.41 or Server: nginx/1.18 tells attackers your exact software version. Remove or obscure it.

⚠️ Set-Cookie without HttpOnly and Secure flags

Cookies without HttpOnly can be stolen via XSS. Without Secure, they're sent over HTTP. Always set both in production.

Best Practices

Set Cache-Control on every response

Explicitly define caching behavior. 'max-age=31536000' for static assets with hashed filenames, 'no-store' for sensitive data.

Add all security headers

HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy should be on every production response.

Use CORS headers correctly

Never use wildcard (*) with credentials. Whitelist specific origins. Set Access-Control-Max-Age to reduce preflight requests.

Always set HttpOnly + Secure on cookies

HttpOnly prevents XSS theft, Secure prevents HTTP transmission. Add SameSite=Strict for CSRF protection.

Remove the Server header

Don't reveal your web server software and version. It gives attackers information about potential vulnerabilities.

Use Content-Disposition for downloads

Set 'attachment; filename=report.pdf' to trigger file downloads instead of displaying in browser.

Enable gzip/Brotli compression

Set Content-Encoding: gzip or br. Reduces transfer size by 60-80% for text-based responses (HTML, CSS, JS, JSON).

Use ETag for conditional requests

Enables 304 Not Modified responses — browser uses cached version without downloading the body again.

Set charset in Content-Type

Always include charset: 'Content-Type: text/html; charset=utf-8'. Prevents encoding issues and garbled text.

Audit with securityheaders.com

Scan your site to check which security headers are missing. Aim for an A+ grade before launching to production.

Response Headers vs Request Headers

AspectRequest HeadersResponse Headers
Sent byClient (browser/app)Server
DirectionClient → ServerServer → Client
PurposeTell server what client needsTell client about the response
Auth exampleAuthorization: Bearer tokenWWW-Authenticate: Bearer
Content-TypeFormat of request bodyFormat of response body
CachingIf-None-Match, If-Modified-SinceCache-Control, ETag, Expires
CookiesCookie: name=valueSet-Cookie: name=value
CORSOrigin: https://app.comAccess-Control-Allow-Origin

Frequently Asked Questions

What are HTTP response headers?
HTTP response headers are key-value pairs sent by the server back to the client along with the response body. They contain metadata about the response — content type, caching rules, security policies, cookies, CORS permissions, and more.
Who sends response headers?
The server sends response headers. When a client makes a request, the server processes it and returns a response that includes a status code, response headers, and optionally a response body. The headers are set by the server application or web server (Nginx, Apache).
What is the Content-Type response header?
Content-Type tells the browser what format the response body is in — application/json for JSON, text/html for HTML pages, image/png for images. The browser uses this to decide how to render or parse the response.
What is Cache-Control?
Cache-Control is a response header that tells browsers and CDNs how long to cache the response. 'max-age=3600' means cache for 1 hour. 'no-store' means never cache. Proper cache headers dramatically improve performance by avoiding unnecessary server requests.
What is Set-Cookie?
Set-Cookie is a response header that instructs the browser to store a cookie. The browser will then automatically send this cookie back with every subsequent request to the same domain. Used for sessions, authentication, preferences, and tracking.
What are security response headers?
Security headers protect against attacks: Strict-Transport-Security (forces HTTPS), Content-Security-Policy (prevents XSS), X-Frame-Options (prevents clickjacking), X-Content-Type-Options (prevents MIME sniffing). Every production site should set these.
What is Content-Security-Policy (CSP)?
CSP is a security header that tells the browser which sources are allowed to load scripts, styles, images, and other resources. It prevents XSS attacks by blocking inline scripts and unauthorized external resources from executing.
How do I view response headers?
Open browser DevTools (F12) → Network tab → click any request → Headers section shows response headers. In terminal, use 'curl -I https://example.com' to see only headers, or 'curl -v' for full request/response including headers.
What is HSTS (Strict-Transport-Security)?
HSTS tells browsers to always use HTTPS for this domain — even if the user types http://. It prevents SSL stripping attacks and accidental unencrypted connections. Set max-age to at least 1 year for production sites.
What are CORS response headers?
CORS headers (Access-Control-Allow-Origin, Access-Control-Allow-Methods, etc.) tell the browser which cross-origin requests are permitted. Without these, browsers block JavaScript from reading responses from different domains.
What is the difference between ETag and Last-Modified?
Both enable conditional caching. ETag is a content hash — if the content changes, the ETag changes. Last-Modified is a timestamp of when the resource was last updated. ETag is more precise (detects any change), Last-Modified is simpler but only second-accurate.
What is the Location header?
The Location header is sent with 301/302/307/308 redirect responses. It tells the browser or client where to go next. For example, after a successful login, the server might respond with 302 and Location: /dashboard.

Related Articles & Tools

Conclusion

HTTP response headers are the invisible control layer of every web interaction. They determine how long content is cached (Cache-Control), how secure the page is (HSTS, CSP), what domains can access the API (CORS), how cookies behave (Set-Cookie flags), and what format the response is in (Content-Type).

For production applications, the essential response headers to configure are: Cache-Control (performance), all security headers (protection), CORS headers (cross-origin access), and proper Content-Type with charset (correct rendering). Get in the habit of checking response headers in DevTools — they tell you everything about how the server is handling your requests.