using relative URLs in nodejs express - node.js

I am using express routing like:
router.get('/test', function(req, res, next) {
if (user logged in)
res.render('test');
else res.redirect('login')
I'm rendering an EJS template file that has CSS links in it and URLs that are
relative to this.
So you might see stuff like this in the test.ejs template:
<link href = "../stylesheets/bootstrap.min.css" rel = "stylesheet">
blee
The problem I encounter is that this route handler accepts URLs that look like
/test and /test/ - This second URL causes my relative URLs to form incorrect absolute URLs.
So if the URLs in my app (when deployed to production using Apache to forward to myapp) are:
example.com/myapp/test
I expect that the CSS be found at
example.com/myapp/stylesheets/bootstrap.min.css
and the blee URL found at
example.com/myapp/blee
and the redirect should go to
example.com/myapp/login
This works as long as the URL coming into the handler is /test
If, however, it is /test/ , the handler accepts it BUT the relative URLs formed are all incorrect.
My dev environment is different from my deploy environment so I can't code full URLs to things because its a longer path before /test. Relative URLS just make better sense.
I've been told not to worry about the URL /test/ coming in as long as my app doesn't create it. But sometimes a user types something into the location box and it sucks that if they type this, it lands inside this handler and generates a broken page.

Related

Node/Express - How to change default root URL

I have a single page application I am working on. The goal is to have the main root route be something other than www.website.com. Something like www.website.com/cool-page This is for SEO purposes. I am not sure if it is best practice or even possible.
Thus far I've been able to change the URL on load using this:
// root route
router.get('*', function(req, res) {
res.redirect('/cool-page');
});
This gives me an error that the page redirected you too many times.
Any advice on this?
Your routing definition looks like it would redirect every request to URLs within the root URL, not just those going to the root URL itself. So it will redirect even the redirected requests going to /cool-page, forming an infinite loop. Try using router.get('/', ... ) instead, I think that would redirect only requests made to the root url,

Appending to url path in express

I am building freeboard using freeboard.io. I am running it on a node server using express. I use
router.get('/', function(req, res, next) {
res.sendFile(path.join(__dirname + '/index.html'));
});
to send the freeboard html file when the base route is hit. However, in order for freeboard to load my saved dashboard I need to append #source=dashboard.json to the url. So the final url would look like
http://localhost:8080/#source=dashboard.json
is there some way I can do this using express? Pretty much when I hit localhost:8080/ I want to append to the url path #source=dashboard.json and respond with the index.html file. Thanks!
The fragment section of the URL is never sent to the server by the browser. See here for more info. Therefore for the server the fragment will always be missing even if the user has entered it on the URL field. In this case redirecting the browser back with the same URL inclusing the fragment may be the wrong thing.

Express static serving wrong path

I am messing around with express.js and have built some basic functionality but am having issues with express static serving from the wrong place if the URL is longer than one directory from root. See the examples below.
I am using the normal documented approach to using static.
app.use(express.static(__dirname + '/public'));
And have set up a couple of routes. eg.
app.get('/signup', function(req, res) {
res.render('signup.ejs');
});
With a 404 catch at the end of the chain.
app.get('*', function(req, res){
res.status(404).render('404');
});
If I hit page such as localhost:3000 or localhost:3000/login which are defined routes, all is well. Even if I hit an undefined route of localhost:3000/foo, I get the 404 rendered correctly with all images present.
However if I go one further and do something like localhost:3000/login/foo all the images are missing and I will get an error in the browsers console with the following address.
http://localhost:3000/login/img/site-brand.png
This happens the same on routes defined with more than one directory too.
I interpreted the docs on the express website that regardless of what was calling for the static image it would be served from the public directory in root, which contains a js, img, and css directories.
My questions are, what have I misinterpreted? and how do I get express to always serve relative to root?
I wrote the whole question then realised that when I had set up the src="" tags in my .ejs files I had used relative paths, not absolute. Rather than delete the question I decided to answer it and post it for others.
So instead of using src="img/my-image.png" it should be src="/img/my-image.png" The leading slash indicates that the request is relative to root not the path that is making the request.
Basic web development stuff there. I should have seen it first time out but its late, and I am cramming my head full of new frameworks which is in turn squeezing the more trivial stuff out of my small brain.

serve a 404 when a locale file is missing in express

I'm using DaftMonk's generator-angular-fullstack, which has been great, except for one small problem I'm having...
I'm using i18next to handle localization, and the way the library works is it attempts to load a locale file from your specified path for the user's given localization setting, ie: /locales/en-US/app.json -- if that doesn't exist, it tries /locales/en/app.json (and in my case finds the file here).
The problem is the way the generator works is it has a route catchall which redirects all 404s to the index.html (the entry point for an angular app). This allows dynamic routing for the single page app.
When this happens, i18next chokes because it was expecting either a 404 or a json locale file, but instead got the index.html page.
I need a way to exclude the /locales path from being handled by this wildcard catch all and serve a 404 rather then the index.html page if a file is missing.
Here is what the express wildcard does:
//is there anyway to write an exclusion to this `/*` wildcard?
app.route('/*')
.get(middleware.setUserCookie, index.index);
/**
* Send our single page app
*/
exports.index = function (req, res) {
res.render('index', {
name: pkg.name,
version: pkg.version,
env: config.env
});
};
//in dev mode
app.use(express.static(path.join(config.root, '.tmp')));
app.use(express.static(path.join(config.root, 'app')));
//in production mode
app.use(express.static(path.join(config.root, 'public')));
How can I write a rule that will redirect /locales/* to serve a 404 if the file isn't found, rather than redirect to index.html?
What about
if (/\/locales\//.test(req.originalUrl) {
send404function()
}
Maybe it's not app.use(), but hopefully you wouldn't have to do this too much.

Node reverse proxy basic routes issue

I have node-reverse-proxy set up like this:
var options = {
pathnameOnly: true,
router: {
'/myapp': '127.0.0.1:9000',
}
}
httpProxy.createServer(options).listen(8000);
The webapp at the root of 9000 has an index.html file with a stylesheet link like this:
<link rel="stylesheet" href="styles/blue.css">
When I hit localhost:9000 directly the html is loaded and the css is found. Then I hit it through the reverse proxy at localhost:8000/myapp, however I get an Error 404 because localhost:9000/styles/blue.css is not found, because the file is served apparently at localhost:9000/myapp/styles/blue.css.
The html of my app of course doesn't know about the reverse proxy so I can't fix this in the index.html. So I guess I'm missing something basic about the setup of the proxy??
I don't know if you've found a workaround for this by now, but I had the exact same problem and think I've worked it out.
When you hit the target endpoint directly localhost:9000 the path is sent through as /, ie just the root. Then when it requests the css etc, it resolves those as expected, from the root.
When you call via the proxy localhost:8000/myapp it routes /myapp to the target and then passes the target service / as the path, at which point it behaves exactly as above.
The problem here is actually at the browser. Because the path is specified as /myapp, it assumes that "myapp" is a filename. Then when it requests the css etc, it peels that back to the last slash and uses that as the base for all relative hrefs, which is why it then asks for /styles/blue.css and not /myapp/styles/blue.css. If you try browsing to localhost:8000/myapp/ - note the trailing slash - then it works because the browser now treats /myapp/ as a component of the path.
Obviously, you can't dictate that users must add the trailing slash. And you can't easily do much about it in the target service, if only because it doesn't see any difference, and anyway you don't want to have to repeat the same solution in every end service. So the answer seems to be to intercept it in the proxy.
This example works, though there might be a more robust way of implementing it. It looks out for cases where the last part of the path is probably a directory component, in which case the request is redirected to force the browser to re-issue it with a trailing slash. It makes that decision based on it not looking like a filename.ext or already having a trailing slash:
httpProxy.createServer(function(req, res, proxy) {
var parsed = url.parse(req.url);
if(!parsed.pathname.match(/(\w+\.\w+|\/)$/)) {
parsed.protocol = 'http';
parsed.host = req.headers.host;
parsed.pathname += '/';
res.writeHead(301, {Location: url.format(parsed)});
res.end();
} else {
proxy.proxyRequest(req, res);
}
}, options);

Resources