Is there a chance to somehow redirect www to non-www URLs in node.js? Since there is no htaccess in node web server I am curious how to do that.
An updated version of jmar777's answer:
Using express
server.use((req, res, next) => {
if (req.headers.host.startsWith('www.')) {
const newHost = req.headers.host.slice(4)
return res.redirect(
301,
`${req.protocol}://${newHost}${req.originalUrl}`,
)
}
next()
})
You're using express, right? If so you can make a route handler that all GET requests go through, checks if they're to a 'www' URL, and redirects to the appropriate non-www URL if appropriate.
app.get('/*', function(req, res, next) {
if (req.headers.host.match(/^www/) !== null ) {
res.redirect('http://' + req.headers.host.replace(/^www\./, '') + req.url);
} else {
next();
}
})
In the world of DevOps and the increasing adoption of hosted platforms, this type of thing should never be handled by code. You should handle the redirect using infrastructure instead. Putting this code into the application means that issues cannot be mitigated by the Operations team should something fail in the apex entry. In addition, while it is fancy and shiny and hip, using the apex as your site url limits the ability of Operations to redirect the site should something go wrong and causes issues when you want to do a blue/green, A/B testing or geo-redirection (in some cases). Your code and app should be url-agnostic.
Even though this question is nearly 3 years old, there are a few subtle issues with the previously posted answers (and their comments), as well as some good advice in the comments that didn't make it back into the answers themselves. Here's a few important things to note:
http://
or https://
in the redirect URI; this makes life suck when switching between dev and prod environments - use req.protocol
instead.req.protocol
reliably behind a proxy performing SSL termination (such as Elastic Load Balancer), you need to make sure that the trust proxy
setting is enabled. This will ensure that req.protocol
returns the protocol that the browser sees, not the protocol that finally made it to your app server./^www/
, but formats the redirect URI with /^www./
. In practice that probably won't bite anyone, but it would result in infinite redirect loops for something like wwwgotcha.example.com
.req.headers.host
instead of req.host
, as the latter strips out the port number. So, if you were to handle a request for www.example.com:3000
, you'd redirect the user to www.example.com
, minus the correct port number.req.originalUrl
when creating redirect URIs, just in case you happen to be running in a mounted "sub app".All that being said, here's my recommended approach that takes the above into consideration:
function wwwRedirect(req, res, next) {
if (req.headers.host.slice(0, 4) === 'www.') {
var newHost = req.headers.host.slice(4);
return res.redirect(301, req.protocol + '://' + newHost + req.originalUrl);
}
next();
};
app.set('trust proxy', true);
app.use(wwwRedirect);
I agree with Sebastian above with a minor tweak and if you are using Express. I would just make it a middleware it will be processed on all requests.
function removeWWW(req, res, next){
if (req.headers.host.match(/^www/) !== null ) {
res.redirect('http://' + req.headers.host.replace(/^www\./, '') + req.url);
} else {
next();
}
}
app.use(removeWWW);
This is a basic exemple of how you could mimic the behavior of the redirect directive of apache in nodejs.
The function redirect takes either a RegExp or a string.
var http, redirect;
http = require("http");
redirect = function(host, res, pattern, redirect){
if (host == pattern || (pattern instanceof RegExp && host.match(pattern))) {
console.log("Redirected " + host);
res.writeHead(302, {
'location': redirect
});
res.end();
}};
http.createServer(function(req, res){
redirect(req.headers.host, res, /^www/, 'http://plouf.url');
redirect(req.headers.host, res, 'www.plouf.url', 'http://plouf.url');
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end('Hello World\n');
}).listen(8000, '127.0.0.1');