When making a HTTP request using node’s HTTP module (namely via the http.request()
or http.get()
methods), it’s possible to receive a status code which indicates a redirect to another URL (301, 302, 307). However unlike the browser’s XMLHttpRequest
, node does not do the leg-work of automatically following the redirect and it’s something you have to handle yourself. Thankfully it’s not too hard to do at all.
var http = require('http');
http.get('http://example.com/a-page-which-redirects', function (res) {
// Detect a redirect
if (res.statusCode > 300 && res.statusCode < 400 && res.headers.location) {
// The location for some (most) redirects will only contain the path, not the hostname;
// detect this and add the host to the path.
if (url.parse(res.headers.location).hostname) {
// Hostname included; make request to res.headers.location
} else {
// Hostname not included; get host from requested URL (url.parse()) and prepend to location.
}
// Otherwise no redirect; capture the response as normal
} else {
var data = '';
res.on('data', function (chunk) {
data += chunk;
}).on('end', function () {
// Do something with 'data'
});
}
});
It’s important to realise that there’s nothing preventing the URL at res.headers.location
redirecting to yet another URL (a re-redirect if you like), so you should consider having some form of loop to repeatedly follow redirect request until you reach an end.
However, this introduces another possible problem you need to be aware of; the infinite redirect loop which can occur if pages redirect between each other (possibly in-directly) infinitely. The HTTP 1.1 standard makes it clear it is the responsibility of the client to detect and handle such situations. It also notes that previous versions of this specification recommended a maximum of five redirections, so it would be a good idea to ensure your implementation allows at least 5 redirects before considering it an infinite loop.
If you’re now wishing there was something out there that did all this for you, look no further than the request
module cooked up by mikeal.
var request = require('request');
request('http://example.com/a-page-which-redirects', function (error, response, body) {
if (!error && response.statusCode === 200) {
// Use body; no need to handle chunks of data *or* redirects!
}
});
Links to further reading could include the documentation on the request
module and a Stack Overflow post asking how redirects could be followed.
Hi Matt,
Thanks for the blog. I have a question on redirecting. I want node server to redirect ‘any request to specific resources’ to a login page. I tried by simply updating req.url and it worked. But the url displayed in browser is still old one. I was wondering whether I can use your approach. You have mentioned ‘make request to res.headers.location’. But how to do that?
This is what I tried.
res.headers.location = “/login.html”;
but error displays when I access the resource.
‘TypeError: Cannot set property ‘location’ of undefined’
Would you mind to elaborate the steps?
Hi Matt, great write up. I was fed up with always writing boilerplate code to handle redirects and didn’t want to use a full fledged solution like `request` so I decided to write a drop in replacement for the native HTTP and HTTPS module that behave exactly the same except they follow redirects. See http://syskall.com/how-to-follow-http-redirects-in-node-dot-js/
Hey Matt,
I would recommend that your statusCode if-statement should only check the range rather than the range and the existence of the Location header. Reason being is if (for whatever reason) you get a statusCod between 300-400 and a location isn’t set, you’ll end up with a socket hang up because it would have moved along to actually retrieving the response body (the else-statement).
Good one! helpful!
Thanks Matt, I have one question:
This follow javascript redirects too?
Thanks in advance.
Hi Herlon,
No… this will only follow HTTP redirects (e.g. using the “Redirect” HTTP header).
Cheers,
Matt