How to make express.static middleware ignore get parameter? - node.js

I have a mobile app that loads images via http. I'm using a GET parameter for cache busting. In QA and Production the images are served via S3 and this works fine. But in development I'm serving them directly from my node / express backend with express.static(). But here the get parameter makes static not find the file. Is there a way to tell express.static to ignore GET parameter? I digged around code but could find anything obvious. Ideas?
+++UPDATE+++
Code and usage example:
//serve assets on the dev server only
if ((process.env.NODE_ENV || 'DEVELOPMENT') == 'DEVELOPMENT') {
app.use(express.static(path.resolve(__dirname,'..','public')));
}
This one works:
localhost:3000/assets/avatars/example.png
This one doesn't:
localhost:3000/assets/avatars/example.png?v=2
+++CLOSED++++
The mistake actually, as suggested below, had nothing to do with static routing. Sincere apologies for wasting your time.

Express is running all the route you define one after another, so if you do:
app.use('/',express.static('/'))
app.get('/myparamter',function(req,res,next){
res.send('This Will never be called')
})
But if you do:
app.get('/myparamter',function(req,res,next){
res.send('This Will be called if you request /myparmeter')
})
// If not another route matches the URL it will server default static file.
app.use('/',express.static('/'))

Related

NodeJs setting up production and development

I was learning NodeJs advance concepts after going through the basic course.
I am following stepehen grinder course where we would be using his folliwng repo
I was initially walking through the repo where somethings were sort of new to me
My main question evolves around his index.js file in repo
This isn't prime question but first he have done something like this
require('./routes/authRoutes')(app);
require('./routes/blogRoutes')(app);
Is this equivalent to something like this
const auth = require('./routes/auth.js')
const profile = require("./routes/profile.js")
app.use('/auth', auth)
app.use('/profile', profile)
Second, Primary question, In his index.js file he have done something like this
if (['production'].includes(process.env.NODE_ENV)) {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve('client', 'build', 'index.html'));
});
}
This does not make sense to me at all, can someone explain me what does the above code do? and an interesting article which can help me comprehend.
Also, Can someone please tell me what does path module do? I went through their do documentation and was able to comprehend that path allows us to access files outside our node project. Is that correct understanding?
Concerning you first question:
It's not the same. app.use(...) defines a middleware that gets executed on all and every routes. Here, both routes files export a function which takes one argument: the application (ExpressJS server) instance.
So, require('./routes/blogRoutes') gives you a function app => {...}, and by adding parenthesis and the app variable as a parameter you immediately execute this function with the current server (application) instance. Which in the end will create all the routes defined in the route file.
Concerning your second question:
The if is testing if the NODE_ENV variable is equal to production. If it is in production mode, app.use(express.static('client/build')); tells ExpressJS to serve static files from the client/build folder.
The rest of the code app.get('*', ...) send the index.html file for calls made to any route except the one defined in the two routes files.
The path.resolve only role is to easily build the absolute path of the index.html file.

What is the best way to conditionally serve static files in Express?

I'm building an application that has two separate parts to it, which on the frontend I am building as two separate Angular apps. I am doing it this way so that I can better divide control access to he codebase and not unnecessarily give some team members access to code they do not need.
So there are two separate applications, served from the same NodeJS server. The app that is served depends on whether the user is logged in. If they are a guest user, they get one version app, if they are registered user they get a privileged version of the app with more features.
How can I conditionally/dynamically serve static files in Express, so as to say, "if User1 is a guest, serve Application A, otherwise serve Application B"?
If it's just one file you're talking about serving (e.g. app-1.js or app-2.js) then you don't need express.static. You can just handle the request in a normal route handler with res.sendFile like so:
app.get('/get-app', function(req, res) {
if (userIsLoggedIn()) {
res.sendFile('/path-to-logged-in-app.js')
} else {
res.sendFile('/path-to-logged-out-app.js')
}
})
More about res.sendFile here.
If you want to serve multiple files via express.static, you'll need two instances of express.static middleware, and another piece of middleware on top of that to modify the request url depending up on the user's logged in status. Maybe something along the lines of the following:
// Middleware function to modify the request url based on user's status
function checkUser(req, res, next) {
if (userIsLoggedIn()) {
req.url = `/app-1/${req.url}`
} else {
req.url = `/app-2/${req.url}`
}
next()
}
// Set up the middleware stack
app.use(checkUser)
app.use('/app-1', express.static(path.join(__dirname, 'app-1')))
app.use('/app-2', express.static(path.join(__dirname, 'app-2')))
More about writing your own middleware here. You also might want to add some logic in checkUser to only prepend to urls requesting static files (e.g. request urls to /assets/foo.js get the prepend treatment but requests to /api/some-api-function do not).
All that said, I'm not that familiar with Angular but I'd suggest investigating other ways to serve logged in / logged out content. I'm assuming there is some concept of components or "views" in Angular, and it's probably a lot cleaner to just render a "LoggedIn" or "LoggedOut" component/view vs. sending a whole different "app".

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.

Serving Angular2 app at a base URL with Express

I have an Angular2 app up and running and a very simple express server. Is it possible to only serve my application when a user visits '/app' (for example)?
If yes how can it be implemented?
I intend to have multiple Angular apps on different URLs and all of these need scripts. Hence a solution which takes care of which script to handle when would be desired.
Edit- Along with the accepted answer, if using the angular-cli, the 'base-href' has to be set to the URL of the app when building the app.
Yes, that's possible.
You have to define that endpoint as the only one:
app.get('/app', function (req, res) {
res.send(/* your application */)
})
You can use this:
// serve the angular web page
app.get('/', app.use(express.static(path.join(__dirname+'/../../public'))));
Note: change the dir name to reach your directory where contains the angular static files.

How to use static folder but also use routing in Express?

I'm having a major issue with Routing in Express.
In my project, there is a folder /public.
Inside /folder I have some other folders like
- public
|- user
|- common
Initially, the only way pages were served by my Node.js server was through res.sendFile(../..). The problem was that the .js files and .css files did not know where to go.
So I added
app.use('/', express.static(__dirname + '/public'));
But now the problem is, if I try to visit /user what happens is, that the static version of the index.html file in that folder is returned, and my route defined in the node app is ignored!
This route - and most importantly the auth middleware is never touched!
How do I reconcile the need to serve files from a static folder, but also may have routes of the same name that I want to control more closely?
app.use('/user', userauth, userRoutes);
Assuming /user is some sort of API I don't think express.static was intended to be used that way. I think the best solution would be to use different routes. You could add something like /api/ to the beginning of all your routes or make sure your static files are organized under /css, /js, /partials, etc.
If you absolutely must support /user for static files AND your api calls you will need to ditch express.static and use something like the Accept header with custom middleware that determines what the browser is asking for. Depending on the scenario this may get complicated to support all the variables. A simple example would be something like this:
app.use(function(req, res, next){
// check Accept header to make sure its a JSON request
if(req.accepts('application/json') && !req.accepts('html')) {
// JSON request so forward request on to the next middleware(eventually hitting the route)
return next();
}
// NOT a JSON request so lets serve up the file if it exists...
// TODO use req.path to check if file exists - if not 404 - will also need to map paths
// to /users to check for /users/index.html if you need to support that
var fileExists = false;
return fileExists ? res.sendFile('...') || res.status(404).send('Not Found');
});
You would have to make sure when the client calls /users it sets the Accept header to application/json. Most client side frameworks have a way to do this for all AJAX requests.

Resources