My middlewares are getting called multiple times and I can't figure out why.
It's a really short code and it is very frustrating as I just started learning express and node.
I don't understand why it's even getting into the second middleware, I didn't use next(), I used res.send().
I am taking an online course and it's the same code as it is described. I also searched stackoverflow but nothing helped.
I did read something about the favicon that calls it a second time, but I can't figure out why this is getting called multiple times.
const express = require("express");
const app = express();
app.use("/", (req, res, next) => {
console.log("This always runs!");
next();
});
app.use("/add-product", (req, res, next) => {
console.log("In first middleware!");
res.send("<h1>Add Product</h1>");
});
app.use("/", (req, res, next) => {
console.log("In second middleware!");
res.send("<h1>Hello from express!</h1>");
});
app.listen(3000);
If I'm opening localhost:3000/add-product I should get in the console:
This always runs!
In first middleware!
but I actually get:
This always runs!
In first middleware!
This always runs!
In second middleware!
This always runs!
In first middleware!
Could it be that the favicon automatically executes all middlewares once? I added this code before the first app.use() call:
app.get("/favicon.ico", (req, res) => res.status(204));
Now I get
This always runs!
In first middleware!
This always runs!
In first Middleware!
I still get it twice.
edit edit edit:
This appears only to happen in chrome.
Don't use app.use for routes that's mainly used for middleware registration you want to use the router. https://expressjs.com/en/4x/api.html#app.use
app.(post|get|delete|put)("route", function(req,res,next){})
in your case it's best to see if your browser is requesting 2 http calls. If so it'll double up.
The browser is sending a request for a favicon. Press F12 on chrome and you will see two requests being made. One of them will be local host and other one will be favicon.ico. Therefore you are seeing two sets of console.log() being printed out to the console.
Instead of reinstalling chrome you could just right click on favicon.ico and click on Block request URL to stop the browser from sending requests for favicon.ico
Was having the same kind of problem but I didn't find any solution online, but I think I found the solution for this. The reason the middleware is being run more than once is that the client is making a request to the server more than once and each of those requests needs to go through the middleware each time.
For example, the first request is the route request itself, then the second one is the request for stuff in public such as images, CSS files, and more. So 2 requests are being made and that means the middleware will be run twice.
My code solution for this is just to have an if statement that checks whether the middleware req.originalUrl contains the file or folder name that is in public, if it doesn't contain it then the middleware code would then be run.
function middleware(req, res, next) {
const condition = !req.originalUrl.includes("css") && !req.originalUrl.includes("image")
if (condition) {
// middleware code
} else if (!condition) {
next()
}
}
I would only suggest you to do this only if you are making a middleware such as a page counter, or a middleware that is only needed to be run once per route request
Problem solved: I reinstalled Chrome and it works fine now. Thanks all!
Related
I have a server that is fully functioning, but I only want it to be accessable when I say. I do this via a discord bot which works fine. I currently have a boolean variable server_on and an if (server on) { do } in all of my app.get and app.post functions. Is there a cleaner way to do this, or is this if statement in every function the only way?
Edit:
Final working code
var block_server_middleware = function (req, res, next) {
if (!server_on) { res.send("server is currently unavailable") }
else { next() }
}
app.use(block_server_middleware)
and the other app.get and app.post functions were not changed at all
This was the only few lines added that made the whole idea work
You can define one middleware function that goes before all your routes are defined:
app.use((req, res, next) => {
if (!server_on) {
// stop all routing
res.send("server not on!");
} else {
// let routing continue
next();
}
});
This will keep your routes from ever getting run until server_on is back to true. If you have any routes you want to leave open all the time, then just place them before this middleware.
You can replace res.send("server not on!"); with whatever is appropriate for your use. You can return a single web page or you can send back a 4xx or 5xx error status (perhaps a 503 error).
Does using app.use(express.static("public")) call the middleware for every request, even if it wasn't a request for a static resource?
It will only get called if a route hasn't dealt with the request already.
Keeping in mind that routes are tested in the order they are registered, take this example:
const express = require('express');
const app = express();
const port = 3000;
app.get('/foo', (req, res) => {
console.log('Foo!');
res.send('Foo!');
});
app.use(function (req, res, next) {
console.log('middleware triggered');
next();
});
app.get('/bar', (req, res) => {
console.log('Bar!');
res.send('Bar!');
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
If I request http://localhost:3000/foo then the server will log:
Foo!
The /foo endpoint matched the request and then called res.send().
If I request http://localhost:3000/bar then it logs:
middleware triggered
Bar!
The middleware kicks in (because it matches the route), called next() to go to the next function that matches the route, and then the /bar handler is called.
It is important to position your static middleware carefully.
If you put it before the route you want to match the request then there are two possible negative effects:
You'll call it when it isn't needed which is inefficient
A static file will match a route instead of an actual route handler
On the other hand, if you put it last then you'll solve the efficiency problem, but some bad route design might mean that something creates a URL which matches an already existing static file and masks it.
It's a good idea to specify a directory that you know will never conflict with a route (e.g. app.use('/static', express.static('public'));) to avoid that possibility. As a bonus it means that any broken links which would normally 404 won't have to go through the static middleware unless the link is pointing in the /static path in the first place.
When registering it like that it, the middleware will run on every request, yes.
Basically because that statement is actually the same as:
app.use("/", express.static("public"))
Calling express.static returns a classic middleware function that will be run on every path you specify in app.use.
If you want it only to kick in on a specific path, you could register it like this:
app.use('/static', express.static('public'));
I have a file shuffleRoute.js where I define this:
router.get("/shuffle?jokers=false", function (req, res) {
cards['a','b','c'];
let shuffledCards = _.shuffle(cards);
res.status(200).send(shuffledCards);
});
I have an index.js where I define:
app.get("/v1/game", require("./routes/shuffleRoute.js"));
I have a game.html where onload I need to do an ajax request to get the shuffled cards. How do I do that?
doing this
$.get( "/v1/game", function(res) {
console.log(res);
});
does not work.
I am getting this error:
jquery-2.2.4.min.js:4 GET localhost:8080/v1/game 500 (Internal Server Error) –
I was using morgan to log things in the server which was incorrectly done.
However, commenting that out gives me this error.
jquery-2.2.4.min.js:4 GET http://localhost:8080/v1/game 404 (Not Found)
May be wrong but i see routes problem here.
When you define routes for express use app.use
var myRoute = require('PathToYourRouteFile');
app.use("/v1/game", myRoute);
In route file. Im asuming you use express router you need to define something like this
youRuoterName.get('/', function(req, res, next) { })
This request will be succes when you go to localhost/v1/game.
If you want another one just do
youRuoterName.get('/shuffle', function(req, res, next) { })
Which will be succes when you go to /v1/game/shuffle.
In your example i see only one route /v1/game/shuffle which clearly not match /v1/game and im not even sure that rest of code works as expected.
So please read docs carefuly http://expressjs.com/en/4x/api.html#router.route
and all should work.
Hope this helps.
I have recently started a new app with Express 4.0, and I really liked the new express.Router() thing.
Something that got me stuck for quite some time was the following behavior:
var app = require('express')(),
router = express.Router();
router.get('/me', function(req, res, next) {
if(someBoolean) {
return next(); //here I expect to get a 404 error from express!
}
res.json({name: 'yourName'});
});
router.get('/:user_id', function() {
//any code here!
});
app.use('/users', router);
I always used next() (in Express 3.x) to either call the next middleware or to force a 404 from the server.
Since /users/me and /users/45 are totally different routes and are not mounted in a way that one should come after another, I wonder why I get code in /users/:user_id evaluated after calling next() in /users/me.
Am I doing something wrong or things are supposed to work different in Express 4.0?
This is working as expected. In Express 4 all middleware/routes are executed in the order that they are added to your app, so the path for your second router.get() is tested and matches because :user_id could be any kind of token, numeric or otherwise (basically any character that isn't /).
You can fix this at least in a couple of different ways:
Don't call next() in your first router.get()
Use a RegExp instead of a string to ensure that user_id only matches a numeric value. For example: router.get(/^\/(\d+)$/, function() {. However then you have to access the param via regexp group index instead of by a name: var user_id = req.params[0].
I'm creating a simple testing platform for an app and have the following code setup as my server.js file in the root of my app:
var restify = require('restify'),
nstatic = require('node-static'),
fs = require('fs'),
data = __dirname + '/data.json',
server = restify.createServer();
// Serve static files
var file = new nstatic.Server('');
server.get(/^\/.*/, function(req, res, next) {
file.serve(req, res, next);
});
// Process GET
server.get('/api/:id', function(req, res) {
// NEVER FIRES
});
It serves static files perfectly, however, when I try to make a call to the /api it just hangs and times out. Imagine I'm missing something stupid here, any help would be greatly appreciated.
node-static is calling next with an error, which means it's never yielding to other handlers.
You can move your other handlers above node-static or ignore it's errors by intercepting it's callback.
I made a working version here: http://runnable.com/UWXHRONG7r1zAADe
You may make yourself sure the api get call is caught by moving the second get before the first. The reason is your api calls routes are already matched by the first pattern.