Node.js www - non www redirection - node.js

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.

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:
Don't hardcode the http:// or https:// in the redirect URI; this makes life suck when switching between dev and prod environments - use req.protocol instead.
Also note that in order to use 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.
The accepted answer has a logic bug, as it matches on /^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.
Be sure to use 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.
As Dário pointed out, you'll typically want to use a 301 redirect when going from www to non-www (or vice versa) for SEO purposes.
The last issue is the most minor, but it's generally safer to use 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);

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();
}
})

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()
})

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');

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.

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);

Related

Google cloud functions replaces double slash in url

Im trying to deploy cors-anywhere on Google Cloud Functions. Im supposed to provide the url after gcp's link.
It looks like this :
https://us-central1-my-project.cloudfunctions.net/my-function/http://dummy.restapiexample.com/api/v1/employees
but it's transformed to :
https://us-central1-my-project.cloudfunctions.net/my-function/http:/dummy.restapiexample.com/api/v1/employees
All the double slashes after the host are transformed to simple ones.
I tried replacing req.url to transform http:/ to http:// but still wont work. Maybe this needs to be fixed in the webserver level.
Here's my function in GCP
var cors_proxy = require('cors-anywhere').createServer({
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: [
'cookie',
'cookie2',
],
// See README.md for other options
});
exports.myFunction = (req, res) => {
req.url = req.url.replace('/my-function/', '/'); // Strip '/my-function' from the front of the URL, else the proxy won't work.
return cors_proxy.emit('request', req, res);
};
Anyone tried to deploy this in a serverless function?
You're using req.url which contains a normalized version of the request URL. You'll want to use req.originalUrl which, as the name suggests, retains the original requested URL. See Express docs for more info.

Express - Allowing for a closing / at the end of a routing path

While routing in Express is quite straightforward I'm having trouble adjusting it to paths that end with a /.
For example, suggest I define the following route:
app.get('/about', (req,res) => res.render('about'));
Now if someone navigates to www.example.com/about the about view is rendered. However, if that same person navigates to www.example.com/about/ the route I specified above will not work. Some people (me included) have gotten used to naturally adding a closing / at the end of paths. I read the Express routing documentation page but it seems the developers were oblivious to this possibility. The only solution I've found thus far is to use regular expressions for each and every route to account for this variation. For example, the route above would become:
app.get(/\/about\/?/, (req,res) => res.render('about'));
Is there a more elegant (or built in) solution to allow for path with a closing / in Express?
This question has already been answered in https://stackoverflow.com/a/15773824/515774
Basically, you will need to add a middleware which will strip the trailing slash and make a redirect request, which will solve your problem.
Following is the code snippet from the previous answer.
app.use(function(req, res, next) {
if (req.path.substr(-1) == '/' && req.path.length > 1) {
var query = req.url.slice(req.path.length);
res.redirect(301, req.path.slice(0, -1) + query);
} else {
next();
}
});
To avoid redirect, you can just rewrite the URL. Reference https://stackoverflow.com/a/13446128/515774
Note: The browser URL stays the same using this approach.
app.use(function(req, res, next) {
if (req.url.slice(-1) === '/') {
req.url = req.url.slice(0, -1);
}
next();
});

In App redirect in expressjs using middleware

I am trying to make a middleware for handling url aliases, what I am doing right now is :
// [...]
module.exports = function() {
return function(req, res, next) {
// getAlias would get an object {alias:"alias/path",source:"/real/path"} or null
var alias = getAlias(req.url);
if(alias) {
req.url = alias.source;
}
next();
};
};
So basicaly I am looking in a store for the requested url and if it is found as an alias I change request.url to the source path to that alias so that express calls the right route.
The problem is request.url and request.path have the same value, but changing request.path does not work while request.url works. In addition I am not sure which one i have to test agains.
Things work when I interact with request.url but just wanted to make sure that I am doing it the proper way.
Any thoughts ?
Rewriting the req.url property is the correct way for internally rerouting requests. That is why there is a req.originalUrl for the cases where one does change the original URL.
This is what the Express documentation states for req.originalUrl:
This property is much like req.url, however it retains the original
request url, allowing you to rewrite req.url freely for internal
routing purposes.
The req.url property isn't documented, but from the statement above you can infer it's meant to be used in the way you explained. It is also used in that way in some of the Express tests.
You can use run-middleware module exactly for that. Just run the handler you want by using the URL & method & data.
https://www.npmjs.com/package/run-middleware
For example:
module.exports = function() {
return function(req, res, next) {
// getAlias would get an object {alias:"alias/path",source:"/real/path"} or null
var alias = getAlias(req.url);
if(alias) {
res.runMiddleware(alias,(status,data)=>(res.status(status).send(data))
}
next();
};
};

get auth portion of url with express.js

I'm building out an API using express.js
(its my first time doing this)
I want to authenticate requests by using the standard auth portion of the url. I want requests to come in as https:// {public-key}:{private-key}#host:port/path
I can't find the auth portion of the url anywhere. req.url is just /path
I found this How to get the full url in Express? which said to do the following:
req.protocol + "://" + req.get('host') + req.url
But that returns only https:// host:port/path
Any help would be great.
As a side note, if this isn't the standard way to authenticate APIs please let me know!
You can use express.basicAuth() middleware to get the username and password sent with the URL.
app.get('/',
express.basicAuth(function(username, password){
console.log(username);
console.log(password);
return (true);
}),
function(req,res){
...
});
Or like the conventional app.use fashion
app.use(express.basicAuth(function(user, pass){
return 'tj' == user & 'wahoo' == pass;
}));

How to Redirect to Single Page Web App in Express for Node

I am writing a website with a single page web app (the rest of the website is just static files which are served). I am trying to write a piece of middleware for express to redirect all requests that follow the pattern 'example.com/app' to 'example.com/app' so that requests such as 'example.com/app/my/specific/page/' will all result in the same page being sent. The key issue with this is that the url in the address bar of the browser must not change so that the javascript app itself can interpret it and display the correct thing.
I could have done something like this:
app.use( '/app', function ( req, res ) {
res.redirect('/app');
});
However, this causes the url of the page to change and a separate HTTP request is assumedly made.
The most obvious alternative solution is to do something like this:
app.use( '/app', function ( req, res ) {
res.sendfile(__dirname + '/public/app/index.html');
});
The issue here is that resources from the page after requests like 'example.com/app/my/specific/page/' will look in the wrong location. For example, if I have an image on the page such as then it will look for example.com/app/my/specific/page/image.jpg. Since no image is returned, it will not display on the page. This happens for all external scripts or stylesheets.
I also tried something like this:
app.use( '/app', function ( req, res ) {
res.sendfile(__dirname + '/public/beta' + url.parse(req.url).pathname);
});
but that was very stupid of me for obvious reasons.
In the end I used this middleware to serve the app's page when appropriate
// all unmatched requests to this path, with no file extension, redirect to the dash page
app.use('/dash', function ( req, res, next ) {
// uri has a forward slash followed any number of any characters except full stops (up until the end of the string)
if (/\/[^.]*$/.test(req.url)) {
res.sendfile(__dirname + '/public/dash/index.html');
} else {
next();
}
});
I then set used a base HTML element with the href attribute pointed to the root.
If you're still trying to accomplish this I may have found a starting point. Alexander Beletsky has a Backbone.js + Express SPA boilerplate repo Located Here.
For a brief article on how it came about you can read his article on Dzone.

Resources