Redirects With Express

May 14, 2019

The res.redirect() function lets you redirect the user to a different URL by sending an HTTP response with status 302. The HTTP client (browser, Axios, etc.) will then "follow" the redirect and send an HTTP request to the new URL as shown below.

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

// The `res.redirect()` function sends back an HTTP 302 by default.
// When an HTTP client receives a response with status 302, it will send
// an HTTP request to the URL in the response, in this case `/to`
app.get('/from', (req, res) => {
  res.redirect('/to');
});
app.get('/to', (req, res) => res.send('Hello, World!'));

const server = await app.listen(3000);

const res = await axios.get('http://localhost:3000/from');
// Axios follows the redirect and sends a GET `/to` request, so the
// response will contain the string "Hello, World!"
res.data;

The res.redirect() function also lets you specify an HTTP status other than 302. The 302 status is considered a temporary redirect, which means search engines will still crawl the existing URL. If you want to indicate the URL has permanently changed, you should send a response with HTTP status 301.

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

app.get('/from', (req, res) => {
  // The optional first parameter to `res.redirect()` is a numeric
  // HTTP status.
  res.redirect(301, '/to');
});
app.get('/to', (req, res) => res.send('Hello, World!'));

const server = await app.listen(3000);

const res = await axios.get('http://localhost:3000/from');
// "Hello, World!"
res.data;

Handling POST Requests

There's some nuances about which status code you should use for POST requests. Strictly speaking, HTTP 301 and 302 are not required to keep the same method and body content when redirecting. If you're redirecting a POST request, you should use HTTP 307 as a replacement for HTTP 302, and HTTP 308 as a replacement for HTTP 301.

const app = require('express')();
// Parser to set `req.body`
app.use(require('body-parser').json());

app.post('/from', (req, res) => {
  res.redirect(307, '/to');
});
app.post('/to', (req, res) => res.send(req.body.message));

const server = await app.listen(3000);

const res = await axios.post('http://localhost:3000/from', {
  message: 'Hello, World!'
});
// "Hello, World!"
res.data;

Here's a brief summary of the tradeoffs between these common redirect statuses.

Tradeoffs between HTTP 301 vs 302 vs 307 vs 308
Want to become your team's Express expert? There's no better way to really grok a framework than to write your own clone from scratch. In 15 concise pages, this tutorial walks you through how to write a simplified clone of Express called Espresso. Get your copy!

Espresso supports:
  • Route handlers, like `app.get()` and `app.post()`
  • Express-compatible middleware, like `app.use(require('cors')())`
  • Express 4.0 style subrouters
As a bonus, Espresso also supports async functions, unlike Express.

Get the tutorial and master Express today!

More Express Tutorials