Express static serving wrong path - node.js

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.

Related

Why not universally route all requests using a one short function?

I've been learning Node JS + Express and pretty much 100% of the dozens of tutorials I've watched either route each specific browser request one-by-one in a main JS file, or they separate routes into separate files (again, one-by-one in their respective files) and link them all back to the index.js file.
I've been trying to understand why these methods in general would be better than just writing something simple like this which handles all get requests universally by going to the proper file in the directory based off what the url is (and can pull the index.html file from each automatically)? It seems like it would be a lot of never ending code for what could be replaced with:
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname+req.path+'/'));
});
Why are the methods I've seen used as opposed to the method I thought of?

ExpressJS static file serve always serves the same file

I have a expressJs setup which looks like this:
// Imports...
const app: express.Application = express();
const port: number = 3001;
const listener = new StatementListenerAPI();
app.use('/listen', listener.getRouter());
app.use('/welcome', router);
if (fs.existsSync('./client')) {
// Running in prod environment with pre built client directory. Serve this.
app.use(express.static('./client'));
}
app.listen(port);
So I have some routers connected to the express app, and at the bottom I declare that the directory client should be served statically. This directory contains an index.html as well as lots of JS, CSS and PNG files. However, no matter which URL I try to access from the express server, it always shows the code of the index.html within the statically served directory. The references to the JS and CSS files used inside the index.html also just return the code of the index.html.
I am using ExpressJS 4.16.3
What am I doing wrong?
Edit: So technically it works if using __dirname + '/client' instead of ./client. What I am now getting is that, when making GET requests from e.g. Postman (therefore "hand-crafting" the HTTP requests), I am always getting the correct results. If I call the resources from within my web browser, it still always shows the website (resolves the index.html). However, now all resources like JS and CSS scripts are being resolved properly, so apperantly Chrome resolves those dependencies properly, I am just wondering why I am still getting the contents of index.html as result when requesting some of the assets or some of the express endpoints via Chrome. API calls via code are working fine, so its only why manual chrome requests show this weird behaviour, at this point I am only asking out of curiosity.
Answer to your original question:
The path supplied to express.static should be relative to the directory from where you launch your node process or an absolute path. To be safe construct an absolute path (ie from the current directory or file). For example:
app.use(express.static(__dirname + '/client'));
Regarding your followup question:
I assume this is because Chrome uses heavy caching and it thinks this folder should return the html file. You can try and reset all caches in Chrome, or just for the page.

How to prevent express server from serving api routes from the static folder

Hi I need some help with how express handles routes.
In setting up my express app, I have something like this:
app.use(express.static('public'));
Next, I mount some api routes:
app.use('/api', myrouter);
app.get('*', function(req, res) {
res.sendFile(path.resolve('public/index.html'));
});
But, when the frontend requests data via an api route, e.g. at 'localhost:3000/api/things', I am seeing in the Express debug logs that at some point (unsure when) it actually tries to serve this request as a static file, like:
send stat "C:\myproject\public\api\things" +230ms
Even though this folder doesn't exist in 'public' and should be solely handled by my api. FYI, the handler for /api/things route is only implemented for the GET method, and does get invoked at some point.
How do I stop express server from also trying to serve api requests from the static folder?
Thanks very much.
Answering my own question... which appears to be a duplicate of this one:
`express.static()` keeps routing my files from the route
So the answer is this one: https://stackoverflow.com/a/28143812/8670745
In short, the app.use() declarations that mount your api routers should appear before the app.use() statements which tell express.static where to serve your static files from. This way, the latter acts as a catchall AFTER api route handling is done. Router engine order matters...
Your answer is misinformed, or rather you've misinterpreted the problem. Your original configuration:
app.use(express.static(__dirname + 'public'));
app.use('/api', myrouter);
Looks absolutely fine because there's no clash between the routes. The threads you've linked too aren't really the same, and I can see why moving the routes in those cases would have worked.
The only thing I'd say is your path to your static folder isn't reliable, you should really use path.join, or actually in your case you can just do express.static('public') - express will infer the folder your app is served from.

Use non-absolute Paths with node.js and express

i'm having issues running my node server on localhost.
right now it only allows me to run it with a static path:
app.get("/", function(req, res){
res.sendFile("/Users/name/Documents/_privat/dungeon/index.html");
});
of course that's not where i wanna go.
i tried many ways to embedd the dynamic path, this is my file-structure:
*dungeonapp
- main.html
- js
--client
---main.js (and others)
--server
---server.js
- style
--style.css
So if I run everything static my application runs on localhost, but it also won't load my css files neither the js files.
Where am i going wrong? all the regular path embedding didn't work like "/../index.html"
Express response sendFile() method has a second options argument where you can express your root path for path resolution. See docs for more information. You can use {root: __dirname} as second argument to sendFile() and file paths will be resolved relative to the javascript file that calls sendFile(). In your case with the directory structure indicated in your question the code on server.js would be:
app.get("/", function(req, res){
res.sendFile("../../main.html", {root: __dirname});
});
This way you can move your project to any folder and sendFile() will continue to work. I think you should reword your question because you are talking about absolute paths and not static paths.
Normally you would do something like have two subfolders in the root of your project, one for server code and one for client (i.e. web) code and then you can use app.use(express.static('<filepath>')) in your server code to serve the static client files.
As an example, in my project root I have 2 folders, one called app and one called web. In the main app.js, I have app.use(express.static(__dirname + '/../web/')); which serves the static content. Normally this would be the first use of app.use() so that none of the other routes need to be checked before your content is served.

ExpressJS incorrectly rewriting paths when navigating directories

I've run into a maddeningly inconsistent issue with Express in a Node application where I am not able to correctly navigate through the built-in directory rendering due to a URL rewrite. It's easier to explain with code:
var express = require('express');
var app = express.createServer();
app.use("/public", express.static("/web/content"));
app.use("/public", express.directory("/web/content"));
app.listen(8888);
Using the uber-simple express server above the contents of /web/content are displayed as a list of links when you navigate to localhost:8888/public. So, for example:
..
index.html
header.jpg
js (folder)
css (folder)
From there if I click on index.html or header.jpg they display correctly, but clicking on the either folder will navigate to (for example) localhost:8888/js, even though the link clearly leads to localhost:8888/public/js. Upon further inpection it's revealed that the request is sent out for the right path (/public/js), but the server returns a 301 - Moved Permanently response that then redirects the browser to /js, which proceeds to display an error page because the content cannot be found. (No, really?)
Attempts to request a specific file beneath these folders (ie: localhost:8888/public/js/main.js) works fine and does not have the same issue.
The maddening part is that it was doing this on my dev box for a while and then simply... stopped. Not sure why. When attempting to deploy, however, the production server started having the same issue even though I can no longer reproduce it in my dev environment. Does anyone know why Express seems so intent on rewriting my URLs to the wrong thing?
Turns out the answer was pretty simple, and I only missed it because of my browser cache. After digging through the Express (well, technically Connect) code and sprinkling it liberally with console.log(), I traced it down to some code in the static middleware that was detecting that the directory contained an index.html file and was attempting to display that instead. Somehow that code got the wrong path, and the invalid redirect happened.
The real problem, though, was that the static handler was acting before the directory middleware could, which is a direct result of the order in which the middleware was declared. As such simply flipping the middleware declaration like so:
app.use("/public", express.directory("/web/content"));
app.use("/public", express.static("/web/content"));
fixed the issue.
Now, I had actually tried this before but did not realize that the 301 that I was sent previously had been cached, and so the browser was redirecting me before even touching the server. After flipping the order AND emptying my cache, I was able to navigate thde directory structure correctly.
Sigh If I had a dollar for every "bug" I've encountered caused by browser cache...

Resources