I was wondering why my router "/posts" is not running or it's just stuck loading its page when I include a middleware of app.use()
const express = require('express');
//Initialize Express
const app = express();
//Middleware
//When I comment this app.use line of code I can access the /posts router but when I left it uncommented
//My localhost sometimes error and keeps on loading
app.use('/posts',()=>{
console.log(' middleware');
});
//Ability to create routes
//ROUTES
app.get("/", (req,res)=>{
res.send('We are on Home page');
});
app.get("/posts", (req,res)=>{
res.send("Welcome back user Ice");
});
//Start Listening to our Server
app.listen(3000);
Based on your code, you're stuck at
app.use('/posts',()=>{
console.log(' middleware');
// You should either call next() here or respond to the HTTP here
})
To understand this, you need to get the concept of middleware in express.
You can imagine middleware like a list of function that a HTTP call should go through, depending on how you arrange it. All middleware registered with express will have access to request object req, the response object res, and the next middleware function. Among the best benefits of middleware pattern is it avoids coupling the sender of a request to the receiver by giving more than one function a chance to handle the request. Both the receiver and the sender have no explicit knowledge of each other.
Types of express middleware
Application level middleware app.use
Router level middleware router.use
Built-in middleware
express.static,express.json,express.urlencoded
Error handling middleware app.use(err,req,res,next)
Thirdparty middleware bodyparser,cookieparser
To better understand why ur code is stucked, lets look at your code again.
const express = require('express');
//Initialize Express
const app = express();
//Middleware
// You registered an application level middleware here, which its route is
// reached via http://localhost:3000/posts
// If you are going to respond here, you should first pass a `req` & `res`
// as a variable to the callback. Then you can just `res.json` `res.send`
// If you want to run some pre-processing of the or checks on the request before
// passing to other middleware, then you should call `next()` when you are done with
// the logic
app.use('/posts',()=>{
console.log(' middleware');
});
//Ability to create routes
//ROUTES
app.get("/", (req,res)=>{
res.send('We are on Home page');
});
app.get("/posts", (req,res)=>{
res.send("Welcome back user Ice");
});
//Start Listening to our Server
app.listen(3000);
If you opt for middleware case (per your question), you need to do this
app.use('/posts',(req,res,next)=>{
console.log(' middleware');
next() // This pass the control to the next middleware registered
});
// Now the request will be passed to this middleware, and runs as you expected
app.get("/posts", (req,res)=>{
res.send("Welcome back user Ice");
});
Related
the code below works:
var express = require('express');
var path = require('path');
var app = express();
app.use('/public', express.static("./public"));
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
But if I change the app.use like this:
var express = require('express');
var path = require('path');
var app = express();
app.use('/public', function(){express.static("./public")});
// browser error "cannot GET /
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
Why? The server doesn't seem to catch any errors
express.static() returns a middleware function when you call it. You have to pass that specific returned function to app.use(). You don't just call express.static() on every request. You call it once, get the returned function and register that as middleware and app.use() will then call that middleware function on every request.
When you do it the correct way like this:
app.use('/public', express.static("./public"));
It's like doing this:
const fn = express.static("./public");
app.use('/public', fn);
or even like this:
const fn = express.static("./public");
app.use('/public', function(req, res, next) {
fn(req, res, next);
});
Hopefully you can see that this code:
app.use('/public', function(){express.static("./public")});
does not do the same thing as any of the correct solutions. This calls express.static() in every request and never calls the returned function that does the actual work for a given request.
Think of express.static("./public") like a factory function. It creates a middleware function that you then pass to app.use() or call yourself with req, res and next as the arguments.
Why? The server doesn't seem to catch any errors
Executing app.use('/public', function(){express.static("./public")}); is not what you want, but it also doesn't create an error. All it does is create a new middleware function (which you ignore) on every single request. It also never calls next to let any other request handlers handle the request so your server would get stuck on every request, but it never actually causes a visible error.
It essentially becomes functionally equivalent to this:
app.use('/public', function(req, res, next) {
// do nothing, just causes the request to get stuck since
// the request is not handled (no response is sent)
// and next is never called
});
The request is never handled and never calls next to advance to other route handlers so the request just gets stuck and will eventually time out.
You can try with:
app.use(express.static(path.resolve(__dirname, './public'), { maxAge: '1d' }));
I am just writing a small NodeJS code with express module. It was said that we can't continue our request to next middleware without using next() method. But, I am able to continue the request to next middle ware without using next().
//III Party
const express = require('express');
// returns express app
const app = express();
app.use('/add',(req,res,next)=>{
console.log('Add Middleware');
res.send('Add product');
});
app.use('/delete',(req,res,next)=>{
console.log('delete Middleware');
res.send('Delete Product');
});
// Middle Ware
app.use('/',(req,res,next)=>{
console.log('First Middleware');
res.send('Hello World');
});
app.listen(3000);
Kindly explain me this.This is the output for my "/delete" request which is handled in second middleware(without using next methode in previous middleware)
The output is totally correct.
Your so called "First Middleware" is actually the last middleware.
I guess you misthought the hierarchy of the path determine the order of middlewares, from / then /a then /a/b then /a/b/c... But this is not the case.
In fact, the order you call app.use determines the priority of the middlewares.
Quote from http://expressjs.com/en/api.html#app.use
Middleware functions are executed sequentially, therefore the order of middleware inclusion is important.
// this middleware will not allow the request to go beyond it
app.use(function(req, res, next) {
res.send('Hello World');
});
// requests will never reach this route
app.get('/', function (req, res) {
res.send('Welcome');
});
When you get /delete, it searches for the first middleware that matches the path, that is
app.use('/delete',(req,res,next)=>{
console.log('delete Middleware');
res.send('Delete Product');
});
Since you didn't call next(), any subsequent middleware that matches the path will not be called. i.e.
app.use('/',(req,res,next)=>{
console.log('First Middleware');
res.send('Hello World');
});
is not called.
That's why you see Delete Product in the response text but not Hello World.
You can experiment yourself by changing the order of app.use and adding or removing next() to see different results.
I understand that one can call next after res.send in an ExpressJS handler, but does res.send 'automagically' call next in any case?
I have the following code
const express = require('express');
var app = express();
app.get('/', (req, res, next) => {
console.log('in route handler')
res.send('Hello World')
});
app.use((req,res, next) => {
console.log('in middleware')
console.log('...........')
})
app.listen(process.env.PORT || 8080)
My console log is
in route handler
in middleware
...........
If I do indeed call next explicitly after res.send I get
in route handler
in middleware
...........
in middleware
...........
and thus it would seem the middleware is being called twice.
Why is this? Is it because the middleware is also called 'directly' in some fashion, regardless of the route? That is, it is simply always called, even when it is after the route handlers? But I thought if it was after the route handlers, to reach the middleware the route handler preceding it has to call next, as here https://derickbailey.com/2016/05/09/in-what-order-does-my-express-js-middleware-execute/, where it says "It turns out the order in which you add the middleware is important. And since the 2nd 'use' method is added after the 'get' handler, it is never called. The 'get' handler short-circuits the middleware when it renders the page, preventing any further middleware from being processed."
Express version 4.16.0, Node version 11.2.0
Thanks for any clarification!
Why is this?
It's because browsers send an additional request to get favicon; When you go to localhost:8080 chrome ( or firefox ) sends a get request to / hence your server matches this route and logs:
in route handler
Immediately after that it sends a second get request to /favicon.ico but your server does not match any route. it continues its way to middlewares mounted after routing and so logs:
in middleware
...........
Of course by calling next() you've called your middleware explicitly after two above request and so:
in route handler
in middleware
...........
in middleware
...........
But I thought if it was after the route handlers, to reach the
middleware the route handler preceding it has to call next
Of course you are right. Add serve-favicon middleware to your app and your custom middleware never get called without calling next() explicitly unless none of the routes does not get matched:
const express = require('express');
var favicon = require('serve-favicon')
var path = require('path')
var app = express()
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
app.get('/', (req, res, next) => {
console.log('in route handler')
res.send('Hello World')
});
app.use((req,res, next) => {
console.log('in middleware')
console.log('...........')
})
app.listen(process.env.PORT || 8080)
By the way this middleware mounted after all routes is proper place for handling 404's because if we get to this point, none of our apps routes got matched.
app.use()
Middleware allows you to have set of actions which your routes should follow. Consider as if all your routes will do some processing before actually performing designated action for that route.
When I ran your code it printed below and Hello World was rendered in both Mozilla(Version 63.0.3 (64-bit)) and Chrome(Version 71.0.3578.80)
in route handler in middleware ...........
res.send()
Now coming to your question, no there is no need to call next() after res.send() is called. Because as soon as it is encountered, it'll send the response immediately. And yes you are correct the order of middleware does matter. So when you added next() after res.send() following actions were performed:
First the '/' route will return Hello World on the browser stop loading
Your middleware will be called twice, once due to next() and 2nd time due to middleware itself.
From what I have read here and here, the order in which you place your middleware function matters, as you can have certain routes not go through the middleware function if it is placed before the route, and the routes which are placed after will go through this middleware function.
I am seeing mixed results as my dev environment is not respecting this and my prod environment is. The code is exactly the same.
What I am trying to do is have my login route not be protected by a token checker middleware function and have the rest of my routes protected by a token.
Here is my code:
routes.get('/login', function(req, res) {
// login user, get token
});
routes.use(function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.headers['access-token'];
// decode token
if (token) {
// validate token
}
else if (req.method === 'OPTIONS') {
next();
}
else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
routes.get('/query/:keywords', function(req, res) {
console.log(req.params.keywords);
// execute query
});
app.use('/', routes);
the /query route is the only one that should have to go through the token middleware function correct? Right now I am getting the /login route also going through the token middleware function, which doesn't make sense as I shouldn't need to have a token to login.
Better yet, if there is a way to target which routes I want protected and which routes I do not want protected, this seems better than having to rely on an "order" of where the middleware function is placed.
First, follow along this usage in ExpressJS:
More than one callback function can handle a route (make sure you specify the next object). For example:
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from B!')
})
You'll notice it's definition is close to what you're declaring on routes.use(yourFunction(...)). However, there's no real reason to do it this way other than following examples you've seen in documentation, which is a good way to start nevertheless.
However, it's a flimsy implementation, express will allow hierarchies within it's .get() .post() methods, that's correct, but this is a use case specific and not what you're looking for.
What you need is to implement your custom auth process using the double callback configuration. do this:
// You can save this function in a separate file and import it with require() if you want
const tokenCheck = function(req, res, next) {
// check header or url parameters or post parameters for token
var token = req.headers['access-token'];
// decode token
if (token) {
// validate token
}
else if (req.method === 'OPTIONS') {
next();
}
else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
routes.get('/login', function(req, res) {
// login user, get token [Unprotected]
});
routes.get('/query/:keywords', tokenCheck, function(req, res) {
console.log(req.params.keywords);
// execute query [Protected with tokenCheck]
});
app.use('/', routes);
You might need to play around with the code above, but it'll guide you on the right direction, this way, you can specify particular routes to execute the tokenCheck(req, res, next) function as you want.
The easiest way to do this is to use Router Middleware to scope Routes that require Authentication and the routes that don't. Since all Routers are Middleware, we can implement them just like any other middleware. Ensuring that we place the Routers and Routes in the order that we would like our Routes to be evaluated.
In the below example, the Express server has 2 routers, a LoginRouter and an ApiRouter.
LoginRouter - Generates a Token when receiving a request to POST /login and returns that to the requester for subsequent use in the /api routes.
ApiRouter - Wraps all other routers, centralizes middleware that needs to be globally applied to all routes under /api. Is only accessible to Authenticated Requests.
The API Router is only accessible if there is a token included in the Header and that token is obtained from the LoginRouter. LoginRouter has no authentication required.
With this setup, you'll keep adding routers after the Authorization Middleware to the API Router via .use() on the ApiRouter.
The below pattern of composing Routers from other Routers is very powerful, scalable and easy to maintain.
server.js
const express = require('express')
const bodyParser = require('bodyParser')
const ApiRouter = require('./routes/api')
const LoginRouter = require('./routes/login')
const port = process.env.PORT || 1337
const server = express()
server.use(bodyParser.json())
server.use('/login', LoginRouter)
server.use('/api', ApiRouter)
server.listen(port, () => console.log(`Listening on ${port}`))
LoginRouter - /routes/login.js
const router = require('express').Router()
router.post('/', (req, res) => {
// Validate Credentials
// some validation code...
// Then create the token for use later in our API
let token = '...'
// Response 200 OK with the token in the message body
return res.status(200).send({token})
})
module.exports = router
ApiRouter - /routes/api/index.js
const router = require('express').Router()
const UsersRouter = require('./routes/api/users')
router.use((req, res, next) => {
let authorizationHeader = req.headers['authorization'] || req.headers['Authorization'] // handle lowercase
let [, token] = authorizationHeader.split(' ')
if (!token) {
return res.sendStatus(403) // Forbidden, you're not logged in
} else {
// validate the token
if (!tokenIsValid) {
return res.sendStatus(403) // Forbidden, invalid token
}
// Everything is good, continue to the next middleware
return next()
}
})
router.use('/users', UsersRouter)
module.exports = router
UsersRouter - /routes/api/users
const router = require('express').Router()
router.get('/', (req, res) => {
// We only get here if the user is logged in
return res.status(200).json({users: []})
})
module.exports = router
The application of the token middleware should not happen to the login route due to route order and the fact the login route never calls the next object. Without more information we really can't trouble shoot what is happening beyond that however you could try inspecting it in your dev environment with a debugger break and looking at the req that hits that middleware.
We can however give you some information on how to try and isolate your .use middleware and how application of middleware order applies so that you can try and separate it from the login route entirely like in the bottom of your question.
When applying middleware to only specific routes you should keep note that order and .use are for middleware that should answer the request before telling express to continue looking for other middleware that come after them in the router that will also handle the request. If you only want it on a few routes, you can add it to only a few routes by being explicit like so:
router.get('/route', [ middleware1, middleware2, ..., middlewareX])
or
router.get('/route', middleware1, middleware2, ..., middlewareX)
both patterns will work. I however find the array pattern a little more palatable since I can define a lot of middle wares I want to apply and then concatenate new middleware for specific logic, and I only need modify where I declare that concatenation to add more functionality. It'd however rare to need that many middleware and you should be able to use either.
You could also section that middleware off to a subset of routes by using a router and applying it as the first middleware to the route chain before the router.
app.use('/user', authentication, userRouter)
or you can put it inside the router as the first middleware with a .use so that it handles all requests.
So remember the general tips about middleware usage:
order matters for middleware application
optional middleware that should be applied on route basis should be applied with the other middleware in order for only that route
error handling middleware must always come last, and have four arguments (err, req, res, next)
use routers to section .use middleware to specific routes and sets of routes
You can find more information about it in the expressjs documentation for middleware
I am building an app with express js which will have different clients like web and mobile. I didnt want to use one app for both as some middleware would be additional burden. For say like session middleware. So is it possible for one project to have two apps. And how would it work?
The app object that you make in express is a function(req,res,next) that is suitable for Express's own middleware chains. So you can use app.use to send requests matching a leading path fragment to an app defined elsewhere.
Docs: http://expressjs.com/api.html#app.use
$ npm install express
//mobile.js
var app = require('express')();
app.get('/', function(req, res){
res.send('Mobile Route')
});
module.exports = app;
//desktopApp.js
var http = require('http');
var express = require('express');
var desktopApp = express();
var mobileApp = require('./mobile.js');
desktopApp.use('/mobile', mobileApp)
desktopApp.use(desktopApp.router);
desktopApp.use(express.errorHandler());
desktopApp.get('/', function(req, res){
res.send('Desktop Route')
});
desktopApp.get('/mobile', function(req, res){
// Because Express respects the order that you set up the middleware chain,
// the mobileApp `/mobile` route gets first dibs to send a response or next()
res.send('Inaccessible Desktop Route')
});
desktopApp.get('/mobile/foobar', function(req, res){
// When mobileApp can't find any suitable route matching this path, it gives
// up, and desktopApp continues to pass the request down the middleware stack.
// It ends up matching this route, where we send a response
res.send('Desktop Route')
});
http.createServer(desktopApp).listen(3000, function(){
console.log('Listening on 3000');
});
// Results
$ curl localhost:3000/
Desktop Route
$ curl localhost:3000/mobile/
Mobile Route
See the vhost example on the express github repository.
You can have a "main" app, which routes the requests to one app or another. You should write a middleware to establish the conditions where one app or another are requested. express.vhost is a good example, but maybe you need other checks than the domain one.
main-app.js
(The file called to start the server.)
// load dependencies
var main = express();
main.use( express.vhost( 'mobile', require( './the-mobile-app' ) );
main.use( express.vhost( '*', require( './the-web-app' ) );
main.listen( /*...*/ )
the-mobile-app and the-web-app.js
var app = express();
//
// setup your application conf, middleware, and routes
//
module.exports = app;
I wanted to share a different approach that I used in a project recently:
function renderAppropriate(template1, template2){
return function(req, res){
if(req.session && req.session.mobileOn){
res.render(template1);
} else {
res.render(template2);
}
};
};
app.get('/', function(req, res, next){
// do some stuff
next()
}, renderAppropriate('someMobileTemplate', 'someDesktopTemplate')
);