I am using node.js and express and I want to show custom error message when the requested page is not found. Currently I am doing it by using a Wildcards. If any of the routes doesn't match then the last route gets invoked. Is there any other better way to do this??
My routes
app.get('/', routes.index);
app.get('/users', user.list);
app.get('/hello', hello.hello);
app.get('/*', error.error);
What you are doing is good. The only thing I would change is the order of routes like so
app.get('/users', user.list);
app.get('/hello', hello.hello);
app.get('/', routes.index);
app.get('/*', error.error);
A good rule to follow is define all least general routes first. As you probably know this basically tells express that if no other route is found show an error message and wild cards are a pretty good way to do it.
Related
I've created a NodeJS Express app. But my express route is invocking multiple routes function, one after another, but I only need one at a time.
My express app.js
app.use(routes)
Express router:
const router = express.Router();
router.post("/product", controller.productFunction)
router.post("/user", controller.userFunction)
router.get("/:id", idController.getId)
Whenever I create a post request for "/product" route, first the productFunction is invocked, but then the "/:id" routes getId function is also get invocked. Same thing happen for /user route as well. Always /:id route is getting invocked.
Is there any way to prevent this?
I even tried this way, but after the homepage loading then again it invockes getId function.
app.get("/", (req, res, next) => {
res.sendFile(..........);
});
app.use(routes);
I am sure that this is not an issue with the router itself.
You can't skip from POST to GET handling. So invocations are caused by different requests.
router.get("/:id", idController.getId) kind of wild card, and <server_url>/favicon.ico will trigger it
If you check it via browser it tries to get favicon or smth else and invokes this handler.
Try to make POST request via curl/Postman and idController.getId should not be called.
It is risky to serve static and process requests on a same level.
You can add some prefix to all your request, like that app.use('/api', routes); then static file will be available on /<file_name> and all server logic will be under /api/<request>
So i have an express app and in the app.js i have this:
app.use('/index', function (req, res, next){
res.sendFile(__dirname+'/index.html');
}
app.get('/script.js',function(req,res){
res.sendFile(__dirname+'/public/script.js');
and after starting the server and type localhost:3000/index and the app works fine but here comes the problem..
when i change the first app.use() function to:
app.use('/', function (req, res, next){}
so that i don't have to type the index part in the URL, all the next get requests respond with index.html page and i tried adding
res.end(); after res.sendFile();
but no other response gets sent after that, how can i solve?
Your / route is acting as a wildcard and capturing all requests, which means that anything not matching a route defined BEFORE this route will be caught by it. You have two options here:
Change app.use to app.get so that you are explicitly only matching / (and only with a GET method)
Move the route to the bottom of all of your routes
As explained on the Express.js API docs for app.use here:
A route will match any path, which follows its path immediately with a “/”. For example: app.use('/apple', ...) will match “/apple”, “/apple/images”, “/apple/images/news”, and so on.
This is a question on how router is handled underneath.
If I have router:
var router = express.Router();
router.get('/', function(req, res) {
res.end('router');
});
app.use('/', router);
If I've fetch anywhere other than http://localhost/, say http://localhost/whatever I'll get a Cannot GET whatever. Who is giving out this message? I think it's the router, is it correct?
Now if I add a middleware after the router.
app.use('/', function(req, res) {
console.log('-------> here');
});
Now if I go to http://localhost/whatever,then the browser never gets any response back and is just hanging there waiting for stuff.
So, it means the middleware architecture knows that if another middleware is added, then router does not have the final say. And it is expecting another route with possibly another router instance to be added. But if not, then router has the final say.
Isn't that kind of inconsistent? Somehow the router, which is itself a middleware, and the app object kind of know what each other is doing? Because router behave a little differently (call next() or give out "Cannot get" message) depending on whether another middleware is added.
I kind of dig into the code I can't really tell, but it looks like the entire middleware architecture is handled by the router object. Can someone explain a bit what's going on? Thanks.
You are missing one key step in your middleware. Middleware is a chain of asynchronous functions. Each one is called, in turn, with a reference to the next one. The expectation is that you pass control to the next middleware in the stack when you are done, which you are not doing.
app.use('/', function(req, res) {
console.log('-------> here');
});
Try this:
app.use('/', function(req, res, next) {
console.log('-------> here');
next();
});
What will happen then is control will get passed to the router just as it did without your middleware. The router cannot find any routes to handle /whatever, so you still get a 404 not found error.
I'm not sure that this is router who's giving "Cannot get" message.
Each middleware and the app itself try to handle the request in the order that they are being called.
If there is no router's or app's get (or post, etc.) able to handle the request, "Cannot get" message appears.
In the first scenario (before adding a middleware after the router), router can't handle the request, so Express looks forward
to find another app.use or app.METHOD, and not finding, it shows "Cannot get" message.
In the second scenario, another app.use after the router does exist, so it handles the request.
Thus, as for me everything is consistent.
Hope my answer helps you, but if your vision doesn't match mine, I'm ready for discussion :P
P.S. Sorry for my English
Before I ask about app.router I think I should explain at least what I think happens when working with middleware. To use middleware, the function to use is app.use(). When the middleware is being executed, it will either call the next middleware by using next() or make it so no more middleware get called. That means that the order in which I place my middleware calls is important, because some middleware depends on other middleware, and some middleware near the end might not even be called.
Today I was working on my application and had my server running in the background. I wanted to make some changes and refresh my page and see the changes immediately. Specifically, I was making changes to my layout. I couldn't get it to work so I searched Stack Overflow for the answer and found this question. It says to make sure that express.static() is beneath require('stylus'). But when I was looking at that OP's code, I saw that he had his app.router call at the very end of his middleware calls, and I tried to figure out why that was.
When I made my Express.js application (version 3.0.0rc4), I used the command express app --sessions --css stylus and in my app.js file the code came setup with my app.router above both the express.static() and require('stylus') calls. So it seems like, if it comes already setup that way, then it should stay that way.
After re-arranging my code so I could see my Stylus changes, it looks like this:
app.configure(function(){
//app.set() calls
//app.use() calls
//...
app.use(app.router);
app.use(require('stylus').middleware(__dirname + '/public'));
app.use(express.static(__dirname + '/public', {maxAge: 31557600000}));
});
app.get('/', routes.index);
app.get('/test', function(req, res){
res.send('Test');
});
So I decided that the first step would be to find out why it is important to even have app.router in my code. So I commented it out, started my app and navigated to /. It displayed my index page just fine. Hmm, maybe it worked because I was exporting the routing from my routes file (routes.index). So next I navigated to /test and it displayed Test on the screen. Haha, OK, I have no idea what app.router does. Whether it is included in my code or not, my routing is fine. So I am definitely missing something.
So Here Is My Question:
Could somebody please explain what app.router does, the importance of it, and where I should place it in my middleware calls? It would also be nice if I got a brief explanation about express.static(). As far as I can tell, express.static() is a cache of my information, and if the application can't find the requested page, it will check the cache to see if it exists.
Note: This describes how Express worked in versions 2 and 3. See the end of this post for information about Express 4.
static simply serves files (static resources) from disk. You give it a path (sometimes called the mount point), and it serves the files in that folder.
For example, express.static('/var/www') would serve the files in that folder. So a request to your Node server for http://server/file.html would serve /var/www/file.html.
router is code that runs your routes. When you do app.get('/user', function(req, res) { ... });, it is the router that actually invokes the callback function to process the request.
The order that you pass things to app.use determines the order in which each middleware is given the opportunity to process a request. For example, if you have a file called test.html in your static folder and a route:
app.get('/test.html', function(req, res) {
res.send('Hello from route handler');
});
Which one gets sent to a client requesting http://server/test.html? Whichever middleware is given to use first.
If you do this:
app.use(express.static(__dirname + '/public'));
app.use(app.router);
Then the file on disk is served.
If you do it the other way,
app.use(app.router);
app.use(express.static(__dirname + '/public'));
Then the route handler gets the request, and "Hello from route handler" gets sent to the browser.
Usually, you want to put the router above the static middleware so that a accidentally-named file can't override one of your routes.
Note that if you don't explicitly use the router, it is implicitly added by Express at the point you define a route (which is why your routes still worked even though you commented out app.use(app.router)).
A commenter has brought up another point about the order of static and router that I hadn't addressed: the impact on your app's overall performance.
Another reason to use router above static is to optimize performance. If you put static first, then you'll hit the hard drive on every single request to see whether or not a file exists. In a quick test, I found that this overhead amounted to ~1ms on an unloaded server. (That number is much likely to be higher under load, where requests will compete for disk access.)
With router first, a request matching a route never has to hit the disk, saving precious milliseconds.
Of course, there are ways to mitigate static's overhead.
The best option is to put all of your static resources under a specific folder. (IE /static) You can then mount static to that path so that it only runs when the path starts with /static:
app.use('/static', express.static(__dirname + '/static'));
In this situation, you'd put this above router. This avoids processing other middleware/the router if a file is present, but to be honest, I doubt you'll gain that much.
You could also use staticCache, which caches static resources in-memory so that you don't have to hit the disk for commonly requested files. (Warning: staticCache will apparently be removed in the future.)
However, I don't think staticCache caches negative answers (when a file does not exist), so it doesn't help if you've put staticCache above router without mounting it to a path.
As with all questions about performance, measure and benchmark your real-world app (under load) to see where the bottlenecks really are.
Express 4
Express 4.0 removes app.router. All middleware (app.use) and routes (app.get et al) are now processed in precisely the order in which they are added.
In other words:
All routing methods will be added in the order in which they appear. You should not do app.use(app.router). This eliminates the most common issue with Express.
In other words, mixing app.use() and app[VERB]() will work exactly in the order in which they are called.
app.get('/', home);
app.use('/public', require('st')(process.cwd()));
app.get('/users', users.list);
app.post('/users', users.create);
Read more about changes in Express 4.
Routing means determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on).
Each route can have one or more handler functions, which are executed when the route is matched.
In Express 4.0 Router, we are given more flexibility than ever before in defining our routes.
express.Router() is use multiple times to define groups of routes.
route used as middleware to process requests.
route used as middleware to validate parameters using ".param()".
app.route() used as a shortcut to the Router to define multiple requests on a route
when we are using app.route(), we are attaching our app with that router.
var express = require('express'); //used as middleware
var app = express(); //instance of express.
app.use(app.router);
app.use(express.static(__dirname + '/public')); //All Static like [css,js,images] files are coming from public folder
app.set('views',__dirname + '/views'); //To set Views
app.set('view engine', 'ejs'); //sets View-Engine as ejs
app.engine('html', require('ejs').renderFile); //actually rendering HTML files through EJS.
app.get('/', function (req, res) {
res.render('index');
})
app.get('/test', function (req, res) {
res.send('test')
})
In express Version 4 we can easily define routes in the following manner:
server.js:
const express = require('express');
const app = express();
const route = require('./route');
app.use('/route', route);
// here we pass in the imported route object
app.listen(3000, () => console.log('Example app listening on port 3000!'));
route.js:
const express = require('express');
const router = express.Router();
router.get('/specialRoute', function (req, res, next) {
// route is now http://localhost:3000/route/specialRoute
});
router.get('/', function (req, res, next) {
// route is now http://localhost:3000/route
});
module.exports = router;
In server.js we imported the router object of the route.js file and apply it in the following manner in server.js:
app.use('/route', route);
Now all of the routes in the route.js have the following base URL:
http://localhost:3000/route
Why this approach:
The main advantage of taking this approach is that now our app is more modular. All the route handlers for a certain route now can be put into different files which makes everything more maintainable and easier to find.
An article by #kelyvinn from 2016, with the intent to demonstrate modularity, includes this code:
// controllers/apis/dogs/index.js
const
express = require('express'),
dogService = require('../../../services/dogs');
let router = express.Router();
router.get('/', dogService.getDogs);
router.get('/:id', dogService.getDogWithId);
module.exports = router;
Is it possible to use express without any template engine?
Yes,
app.get('/', function(req, res){
res.render('index.html');
});
should just work
UPDATED
Some might have concerns that sendFile only provides client side caching. There are various ways to have server side caching and keeping inline with the OP's question one can send back just text too with send:
res.send(cache.get(key));
Below was the original answer from 3+ years ago:
For anyone looking for an alternative answer to PavingWays, one can also do:
app.get('/', function(req, res) {
res.sendFile('path/to/index.html');
});
With no need to write:
app.use(express['static'](__dirname + '/public'));
For anyone having the need to immediately use regular HTML without jade in a new express project, you can do this.
Add a index.html to the views folder.
In app.js change
app.get('/', routes.index);
to
app.get('/', function(req, res) {
res.sendfile("views/index.html");
});
UPDATE
Use this instead. See comment section below for explanation.
app.get('/', function(req, res) {
res.sendFile(__dirname + "/views/index.html");
});
You can serve static files automatically with Express like this:
// define static files somewhere on top
app.use(express['static'](__dirname + '/your_subdir_with_html_files'));
Actually this should be express.static(...) but to pass JSLint above version works too ;)
Then you start the server and listen e.g. on port 1337:
// app listens on this port
app.listen(1337);
Express now serves static files in /your_subdir_with_html_files automatically like this:
http://localhost:1337/index.html
http://localhost:1337/otherpage.html
This is all out of date - correct answer for 3x, 4x is
The second answer here:
Render basic HTML view?
In your main file:
app.get('/', function(req, res){
res.render('index');
});
Your index.jade file should only contain:
include index.html
where index.html is the raw HTML you made.