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 bodyResponse Header Categories
| Category | Headers | Purpose |
|---|---|---|
| Content | Content-Type, Content-Length, Content-Encoding, Content-Disposition | Describe what the response body contains and how to handle it |
| Caching | Cache-Control, ETag, Last-Modified, Expires, Vary | Control how long browsers and CDNs store the response |
| Security | CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy | Protect against XSS, clickjacking, and other attacks |
| CORS | Access-Control-Allow-Origin, Allow-Methods, Allow-Headers, Allow-Credentials | Control which domains can access the API from browsers |
| Cookies | Set-Cookie | Store data on the client (sessions, preferences, auth) |
| Redirects | Location | Tell the client to navigate to a different URL |
| Connection | Connection, Transfer-Encoding, Keep-Alive | Manage the TCP connection lifecycle |
| Server Info | Server, Date, X-Powered-By | Server 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; includeSubDomainsForces 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.comControls 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: DENYPrevents 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: nosniffPrevents 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-originControls 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 sectionFirefox 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 panelVS Code REST ClientSend request → response shows headers above the bodyCommon 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
Explicitly define caching behavior. 'max-age=31536000' for static assets with hashed filenames, 'no-store' for sensitive data.
HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy should be on every production response.
Never use wildcard (*) with credentials. Whitelist specific origins. Set Access-Control-Max-Age to reduce preflight requests.
HttpOnly prevents XSS theft, Secure prevents HTTP transmission. Add SameSite=Strict for CSRF protection.
Don't reveal your web server software and version. It gives attackers information about potential vulnerabilities.
Set 'attachment; filename=report.pdf' to trigger file downloads instead of displaying in browser.
Set Content-Encoding: gzip or br. Reduces transfer size by 60-80% for text-based responses (HTML, CSS, JS, JSON).
Enables 304 Not Modified responses — browser uses cached version without downloading the body again.
Always include charset: 'Content-Type: text/html; charset=utf-8'. Prevents encoding issues and garbled text.
Scan your site to check which security headers are missing. Aim for an A+ grade before launching to production.
Response Headers vs Request Headers
| Aspect | Request Headers | Response Headers |
|---|---|---|
| Sent by | Client (browser/app) | Server |
| Direction | Client → Server | Server → Client |
| Purpose | Tell server what client needs | Tell client about the response |
| Auth example | Authorization: Bearer token | WWW-Authenticate: Bearer |
| Content-Type | Format of request body | Format of response body |
| Caching | If-None-Match, If-Modified-Since | Cache-Control, ETag, Expires |
| Cookies | Cookie: name=value | Set-Cookie: name=value |
| CORS | Origin: https://app.com | Access-Control-Allow-Origin |
Frequently Asked Questions
What are HTTP response headers?
Who sends response headers?
What is the Content-Type response header?
What is Cache-Control?
What is Set-Cookie?
What are security response headers?
What is Content-Security-Policy (CSP)?
How do I view response headers?
What is HSTS (Strict-Transport-Security)?
What are CORS response headers?
What is the difference between ETag and Last-Modified?
What is the Location header?
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.
