Skip to main content

Express Request Headers

Introduction

HTTP headers are an essential part of the communication between clients and servers on the web. They contain important metadata about the request or response such as content type, authentication credentials, caching directives, and more. In Express.js applications, being able to access and manipulate request headers is a fundamental skill for building robust web applications.

This guide will walk you through everything you need to know about working with request headers in Express.js, from basic access to advanced usage patterns.

Understanding HTTP Headers

Before diving into Express-specific code, let's understand what HTTP headers are:

HTTP headers are simple key-value pairs sent at the beginning of HTTP requests and responses. They define the operating parameters of an HTTP transaction.

Common request headers include:

  • Content-Type: Indicates the media type of the resource
  • Authorization: Contains credentials for authenticating a user
  • User-Agent: Identifies the client application or browser
  • Accept: Specifies which content types the client can process
  • Cookie: Contains stored HTTP cookies

Accessing Request Headers in Express

Express provides a simple and intuitive way to access request headers through the req.headers object.

Basic Header Access

javascript
const express = require('express');
const app = express();

app.get('/headers', (req, res) => {
// Access all headers
const allHeaders = req.headers;

// Access a specific header
const userAgent = req.headers['user-agent'];

res.send({
allHeaders,
userAgent
});
});

app.listen(3000, () => {
console.log('Server running on port 3000');
});

When you make a request to /headers, you would see a response containing all the headers your browser sent, plus the specific User-Agent header value.

Case-Insensitivity of Headers

An important thing to note is that header names in Express are case-insensitive. Express normalizes all header names to lowercase:

javascript
app.get('/case-test', (req, res) => {
// All of these will access the same header
const contentType1 = req.headers['content-type'];
const contentType2 = req.headers['Content-Type'];
const contentType3 = req.headers['CONTENT-TYPE'];

res.send({
contentType1,
contentType2,
contentType3
});
});

All three variables will contain the same value because Express converts header names to lowercase.

Convenience Methods for Common Headers

Express provides convenience methods for accessing some commonly used headers:

The req.get() Method

javascript
app.get('/get-header', (req, res) => {
// Using the req.get() method
const contentType = req.get('Content-Type');
const accept = req.get('Accept');

res.send({
contentType,
accept
});
});

The req.get() method is case-insensitive and provides a cleaner way to access headers compared to directly using req.headers.

Working with Specific Headers

Let's explore how to work with some commonly used headers:

Content-Type Header

The Content-Type header tells the server what kind of data is being sent:

javascript
app.post('/api/data', (req, res) => {
const contentType = req.get('Content-Type');

if (contentType !== 'application/json') {
return res.status(415).send('Unsupported Media Type - Please send JSON');
}

// Process the JSON data
res.send('JSON data received successfully');
});

Authorization Header

The Authorization header is used for authenticating users:

javascript
app.get('/protected', (req, res) => {
const authHeader = req.get('Authorization');

if (!authHeader) {
return res.status(401).send('Authentication required');
}

// Basic Auth example
if (authHeader.startsWith('Basic ')) {
const base64Credentials = authHeader.slice('Basic '.length);
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [username, password] = credentials.split(':');

if (username === 'admin' && password === 'password') {
return res.send('Welcome, admin!');
}
}

res.status(401).send('Invalid credentials');
});

Accept Header

The Accept header specifies which content types the client can understand:

javascript
app.get('/content', (req, res) => {
const acceptHeader = req.get('Accept');

if (acceptHeader.includes('application/json')) {
return res.json({ message: 'Here is some JSON data' });
}

if (acceptHeader.includes('text/html')) {
return res.send('<h1>Here is some HTML content</h1>');
}

res.send('Plain text response as fallback');
});

User-Agent Header

The User-Agent header helps identify the client:

javascript
app.get('/detect-client', (req, res) => {
const userAgent = req.get('User-Agent');
let clientInfo = 'Unknown client';

if (userAgent.includes('Mozilla')) {
clientInfo = 'Browser';

if (userAgent.includes('Chrome')) {
clientInfo = 'Chrome browser';
} else if (userAgent.includes('Firefox')) {
clientInfo = 'Firefox browser';
}
} else if (userAgent.includes('PostmanRuntime')) {
clientInfo = 'Postman';
} else if (userAgent.includes('curl')) {
clientInfo = 'curl command-line tool';
}

res.send(`You are using: ${clientInfo}`);
});

Real-world Applications

Let's look at some practical applications of handling request headers in Express:

Content Negotiation

Content negotiation allows the server to serve different formats based on what the client can accept:

javascript
app.get('/api/products/:id', (req, res) => {
const productId = req.params.id;
const product = {
id: productId,
name: 'Smartphone',
price: 599.99,
description: 'Latest model with advanced features'
};

const acceptHeader = req.get('Accept');

if (acceptHeader.includes('application/json')) {
return res.json(product);
}

if (acceptHeader.includes('application/xml')) {
const xml = `
<product>
<id>${product.id}</id>
<name>${product.name}</name>
<price>${product.price}</price>
<description>${product.description}</description>
</product>
`;
res.type('application/xml');
return res.send(xml);
}

// Default to plain text
res.type('text/plain');
res.send(`Product: ${product.name}, Price: $${product.price}`);
});

API Versioning

Headers can be used to handle API versioning:

javascript
app.get('/api/features', (req, res) => {
const apiVersion = req.get('X-API-Version') || '1';

if (apiVersion === '1') {
return res.json({
features: ['basic search', 'user profiles']
});
}

if (apiVersion === '2') {
return res.json({
features: ['advanced search', 'user profiles', 'real-time notifications', 'social sharing']
});
}

res.status(400).json({ error: 'Unsupported API version' });
});

Caching and Conditional Requests

Headers like If-Modified-Since enable efficient caching:

javascript
const lastModified = new Date('2023-01-01').toUTCString();

app.get('/api/data', (req, res) => {
const ifModifiedSince = req.get('If-Modified-Since');

if (ifModifiedSince && new Date(ifModifiedSince) >= new Date(lastModified)) {
// Resource hasn't been modified
return res.status(304).end(); // 304 Not Modified
}

// Set the Last-Modified header
res.set('Last-Modified', lastModified);
res.json({
data: 'This is the actual data',
timestamp: new Date().toISOString()
});
});

Creating Custom Headers

You can also check for custom headers that your frontend or API clients might send:

javascript
app.get('/api/custom-header-demo', (req, res) => {
const apiKey = req.get('X-API-Key');
const clientId = req.get('X-Client-ID');

if (!apiKey) {
return res.status(400).json({ error: 'Missing API key header' });
}

// Log client information
console.log(`Request received from client: ${clientId || 'unknown'}, with API key: ${apiKey}`);

res.json({ success: true, message: 'Custom headers received' });
});

Middleware for Header Processing

For more complex applications, you might want to create middleware to process headers:

javascript
// Authentication middleware using headers
function authMiddleware(req, res, next) {
const apiKey = req.get('X-API-Key');

if (!apiKey) {
return res.status(401).json({ error: 'API key required' });
}

// Validate API key (in a real app, you'd check against a database)
if (apiKey !== 'your-valid-api-key') {
return res.status(403).json({ error: 'Invalid API key' });
}

// Add user info to the request object for later middleware/routes
req.user = { authorized: true };
next();
}

// Use the middleware for protected routes
app.get('/api/protected-data', authMiddleware, (req, res) => {
res.json({ secretData: 'This is protected information' });
});

Security Considerations

When working with headers, keep these security aspects in mind:

javascript
app.use((req, res, next) => {
// Set security headers
res.set('X-Content-Type-Options', 'nosniff');
res.set('X-Frame-Options', 'DENY');
res.set('X-XSS-Protection', '1; mode=block');
next();
});

app.get('/secure-endpoint', (req, res) => {
// Validate Origin header for CORS requests
const origin = req.get('Origin');
const allowedOrigins = ['https://trusted-site.com', 'https://another-trusted-site.com'];

if (origin && !allowedOrigins.includes(origin)) {
console.log(`Rejected request from unauthorized origin: ${origin}`);
return res.status(403).send('Forbidden');
}

res.send('Secure data');
});

Summary

Express.js provides straightforward methods for working with HTTP request headers, allowing you to:

  • Access all headers using the req.headers object
  • Get specific headers with req.get('Header-Name') or req.headers['header-name']
  • Use headers for authentication, content negotiation, and API versioning
  • Create middleware to process headers consistently across routes

Headers are a fundamental aspect of HTTP communication and mastering them will help you build more sophisticated and robust web applications.

Additional Resources

Practice Exercises

  1. Create an Express endpoint that returns different responses based on the Accept-Language header.
  2. Implement a rate-limiting middleware that uses the X-Rate-Limit header to inform clients about their remaining requests.
  3. Build a simple authentication system using the Authorization header with JWT tokens.
  4. Create a logging middleware that captures and logs important request headers for debugging purposes.
  5. Implement content negotiation for an API that can respond with JSON, XML, or CSV formats based on the Accept header.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)