# Important HTTP Response Headers Every Developer Should Know

Published: (December 25, 2025 at 10:11 AM EST)
5 min read
Source: Dev.to

Source: Dev.to

Why HTTP Headers Matter for Backend Developers

HTTP headers are metadata sent with every server response. They tell browsers how to:

  • Cache resources – improve performance.
  • Enforce security policies – protect your app.
  • Handle content – shape the user experience.

Mis‑configured headers can lead to vulnerabilities, slow load times, or broken functionality. Let’s fix that.

1. Content-Type & Content-Disposition

Purpose – Tells the browser what type of data you’re sending and how to handle it.

DirectiveDescription
Content-TypeMIME type (e.g., application/json, text/html, application/pdf).
Content-Dispositioninline (display in browser) or attachment (force download).

Example (raw TCP server)

import { open } from "node:fs/promises";
import net from "node:net";

const server = net.createServer(async (socket) => {
  const fileHandle = await open("report.pdf");
  const { size } = await fileHandle.stat();
  const readStream = fileHandle.createReadStream();

  socket.write("HTTP/1.1 200 OK\r\n");
  socket.write("Content-Type: application/pdf\r\n");
  socket.write(`Content-Length: ${size}\r\n`);
  socket.write('Content-Disposition: attachment; filename="report.pdf"\r\n');
  socket.write("\r\n");

  readStream.pipe(socket);
});

server.listen(8080);

Why it matters – Without Content-Type, browsers may misinterpret the payload. Without Content-Disposition, PDFs might open in‑browser when you intend a download.

2. Cache-Control

Purpose – Controls how and for how long browsers cache your responses.

DirectiveEffect
no-storeNever cache (useful for sensitive data).
no-cacheCache but re‑validate on every request.
max-age=3600Cache for 1 hour.
public / privateShared caches vs. user‑specific caches.

Express.js Example

import express from "express";

const app = express();

app.get("/api/profile", (req, res) => {
  res.set("Cache-Control", "private, no-cache");
  res.json({ user: "John Doe" });
});

app.get("/static/logo.png", (req, res) => {
  // Cache for 1 year
  res.set("Cache-Control", "public, max-age=31536000");
  res.sendFile("./logo.png");
});

app.listen(3000);

Impact – Proper caching can reduce server load by 60‑80 % and dramatically improve page‑load speed.

3. Content-Security-Policy (CSP)

Purpose – Mitigates XSS attacks by restricting where resources can be loaded from.

Common Directives

default-src 'self'               // Only load from your own origin
script-src 'self' https://cdn.example.com
img-src *

Implementation (Express middleware)

app.use((req, res, next) => {
  res.set(
    "Content-Security-Policy",
    "default-src 'self'; script-src 'self' https://trusted-cdn.com; img-src *"
  );
  next();
});

Security benefit – Blocks ~90 % of XSS attacks by preventing inline scripts and unauthorized resource loading.

4. Strict-Transport-Security (HSTS)

Purpose – Forces browsers to always use HTTPS, protecting against man‑in‑the‑middle attacks.

Example

app.use((req, res, next) => {
  res.set(
    "Strict-Transport-Security",
    "max-age=31536000; includeSubDomains"
  );
  next();
});
  • max-age=31536000 → enforce HTTPS for 1 year.
  • includeSubDomains → apply to all subdomains.

Critical note – Once set, browsers will refuse plain‑HTTP connections to your domain for the specified duration.

5. X-Content-Type-Options

Purpose – Stops browsers from MIME‑type sniffing, which can lead to execution of malicious content.

Usage

app.use((req, res, next) => {
  res.set("X-Content-Type-Options", "nosniff");
  next();
});

Why it’s essential – Prevents a .txt file that contains JavaScript‑like content from being executed as a script.

6. CORS Headers (Cross‑Origin Resource Sharing)

Purpose – Controls which external origins may access your API.

Example

app.use((req, res, next) => {
  res.set("Access-Control-Allow-Origin", "https://myapp.com");
  res.set("Access-Control-Allow-Methods", "GET, POST, PUT");
  res.set(
    "Access-Control-Allow-Headers",
    "Content-Type, Authorization"
  );
  next();
});

Real‑world scenario – Your React frontend (myapp.com) calls a Node.js API (api.myapp.com). Without these headers the browser blocks the request.

Purpose – Sends session cookies securely.

Example

app.post("/login", (req, res) => {
  res.cookie("sessionId", "abc123", {
    httpOnly: true,   // Prevents JavaScript access (XSS protection)
    secure: true,     // Sent only over HTTPS
    sameSite: "strict", // CSRF protection
    maxAge: 3600000   // 1 hour
  });
  res.json({ success: true });
});

Security Impact

AttributeEffect
httpOnlyBlocks client‑side script access to the cookie.
secureCookie is transmitted only over HTTPS.
sameSiteMitigates CSRF attacks (strict or lax).
maxAgeControls cookie lifetime.

Practical Checklist for Production

Before you ship, verify that your Node.js app sets the following headers (or their appropriate equivalents):

  • Content-Type – always present and accurate.
  • Content-Disposition – used where download behavior is required.
  • Cache-Control – tuned per endpoint (public vs. private, max‑age, no‑store).
  • Content-Security-Policy – defined with a whitelist‑only approach.
  • Strict-Transport-Security – enabled on HTTPS‑only services.
  • X-Content-Type-Options: nosniff.
  • ✅ CORS headers (Access-Control-Allow-*) – only on routes that need cross‑origin access.
  • ✅ Secure Set-Cookie attributes (httpOnly, secure, sameSite, appropriate maxAge).
  • Referrer-Policy – e.g., no-referrer-when-downgrade or stricter, to control referrer leakage.
  • Feature-Policy / Permissions-Policy – restrict use of powerful browser features (e.g., geolocation, camera).
  • X-Frame-Options: DENY or SAMEORIGIN – prevent click‑jacking.

Tip: Automate header checks with integration tests or use a middleware library like helmet (npm i helmet) to apply many of these defaults with a single line:

import helmet from "helmet";
app.use(helmet());

TL;DR

  • Headers are not optional – they’re a core part of a production‑grade API.
  • Configure them once, test them often – a small mis‑step can expose you to serious risks.
  • Leverage existing middleware (Helmet, cors, compression) to avoid reinventing the wheel.

Now go ahead and make your Node.js services secure, performant, and professional!

  • Cache-Control – Set based on content type
  • Content-Security-Policy – Block XSS attacks
  • Strict-Transport-Security – Enforce HTTPS
  • X-Content-Type-Options: nosniff – Prevent MIME‑type sniffing
  • CORS headers – Enable safe communication with the frontend
  • Secure cookie attributes – Protect session cookies (e.g., HttpOnly, Secure, SameSite)

Conclusion

HTTP headers are your first line of defense and a key lever for performance optimization. The examples shown—especially the low‑level net module approach—demonstrate that headers are just strings you control. Whether you’re working with raw TCP sockets or a framework like Express.js, understanding these headers makes you a more security‑conscious and performance‑aware developer.

  1. Audit your current application’s headers using the browser’s DevTools (Network tab).
  2. Add any missing security headers today—your users’ data depends on it.

Next Steps

  • Test your headers at
  • Aim for an A+ rating
Back to Blog

Related posts

Read more »