serve a 404 when a locale file is missing in express - node.js

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.

Related

Heroku Node/React Deployment Routes Everything to index.html

I have an app.js node main file where I define my api path as the following
app.get('/api/users', UserController.get);
Below in the same file I have the following
app.use(express.static(path.resolve(__dirname, "./front/build")));
app.get("*", function (request, response) {
response.sendFile(path.resolve(__dirname, "./front/build", "index.html"));
});
The index.html successfully serves React App.
If I open my heroku app somewhere at my-app.herokuapp.com it will open the React app which is intended but the Problem is my-app.herokuapp.com/api/users also serves index.html file instead of JSON that the endpoint is supposed to return.
I tried
I replaced endpoint route definition to come before the "" definition (didn't suffice)
EVEN more, I removed redirection to index.html but heroku still opens the index.html page with any type of request (the "" redirection still works). So, it might have cached something?
Is it about cache (how to clean?) or any other suggestions?
You should create routes and work in a proper flow for each functionality,
For Example:
//app.js
app.use("/api/user",userRoutes);
//UserRoutes
router.post("/signup",UserController.signup);
//UserController
exports.signup = async (req,res,next) => {
//Signup function to add a new user when the user provides required info
}
In this way, you code will be easily accessible and much efficient

Node Js Express Static File fails when URL get

I am new to Node Js and doing some practice examples. Static files doesn't serve properly when sending get request as url id.
app.use(express.static('public'));
// It works. Static files loaded properly from http://localhost:3000/themify-icons.css
app.get('/about', (req,res) => {
res.render('about', {
title: 'About'
});
});
// It opens productdetail.ejs but Static files failed here.
// When I check the 'css' from view page source, Its locating to http://localhost:3000/product/themify-icons.css
app.get('/product/:id',(req,res) => {
// console.log(req.params.id);
res.render('productdetail', {
title:'Product Details'
});
});
app.listen(3000);
app('/product/:id') opens productdetail.ejs but Static files failed here. When I check the 'css' from view page source, Its locating to http://localhost:3000/product/themify-icons.css.
I understand its adding 'product' in the path. How do I resolve this even in this url id get method also?
If the browser is requesting http://localhost:3000/product/themify-icons.css, but you want it to just request http://localhost:3000/themify-icons.css, then change the url in the tag to have a leading /. So, instead of
"themify-icons.css"
use:
"/themeify-icons.css"
In your <style> or <link> tag. This should be true for all static resources that you don't want the path from the page URL to be added to.
When you have only a filename, the browser takes the path from the page URL and adds that to the filename. When you have a leading /, then the browser just takes the protocol, host and port from the page URL, not the path.
If your 'public' folder is directly in the project root, write
app.use(express.static(path.join(__dirname, 'public')));
instead of
app.use(express.static('public'));
to get the correct path relative from the project root.
__dirname will refer to the folder in wich your current script is executed.
Note: you need to require the "path" module:
let path = require('path');

using relative URLs in nodejs express

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.

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.

express serves index.html even when my routing is to a different file

I have a public directory with the files index.html and index-08.html in it.
With the code below, I expect index-08.html to be served. But instead, index.html gets served with a browser request of localhost:3000
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', function(req, res) {
res.sendFile('public/index-08.html');
});
But if I change the file name of index.html to something else, say not-index.html, then the correct file index-08.html gets served.
Can you please help me understand why this happens ?
This is because you declared app.use(express.static) before app.get('/'). Express checks routes in the order they are declared, and since index.html is a default filename which is used by static middleware, it shows index.html content.
To fix this you may either put app.use(express.static) after app.get('/'), or set index property of static second argument to non-existing file (false doesn't seem to work):
app.use(express.static(path.join(__dirname, 'public'), {index: '_'}));

Resources