In my app.js
app.use(flash());
app.use(function (req, res, next) {
res.locals.messages = require('express-messages')(req, res);
next();
});
and in my jade file I have
!= messages()
I open the page it says undefiend is not a function function. I already restarted my server, I don't know what's wrong.
If the != messages() causes the problem then the error must occur on the server while rendering the jade file. The jade compiler is povided with a data object that contains a message method.
This message method is provided with res.locals.messages and set with the express-messages call. From all I know up to now I would asume that you positioned the code above after you configured the route to page. Then the page is rendered before you set the message method. In that case reorder the app.use calls, so the route is defined at last.
Hope that help!
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).
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!
I am attempting to run the function isUserAuthenticated on every request to the server by requiring it in app.js and 'using' it as so: app.use(authenticate.isUserAuthenticated).
I have an /authenticate callback route that is being POSTED to by our SAML Identity Provider which contains the information required to validate the user and the session. This is what is inside my authenticate.js file:
module.exports = router;
module.exports.isUserAuthenticated = function(req, res, next) {
console.log(req.cookies.subject);
if (req.cookies.subject) {
console.log(req.cookies.subject)
return next();
} res.redirect("LINK TO IDP FOR VERIFICATION, callback func. is then ran to get value of user and session");
}
As referenced, this authentication function is being required and used in app.js: authenticate = require('./routes/authenticate'), and app.use(authenticate.isUserAuthenticated).
The problem: No matter what variation of the if statement to verify if the subject cookie is present in the request, the authentication check is not being fired and the redirect to the IDP authentication route is not being redirected too. The console.log checks in the code above are returning:
undefined, and
{}.
Authentication was working on a single route when I was using the isUserAuthenticated function manually like this: router.use('/', isUserAuthenticated, function(req, res, next) {..., but I am trying to use this function globally so I don't have to manually incorporate this middleware on each route.
Any advice/suggestions would be greatly appreciated. Thank you.
as suggested in comment,
you can move the isUserAuthenticated function to app.js. It'd look something like this
app.use(function(req, res, next) {
if (req.cookies.subject) {
next();
}
else
res.redirect("LINK TO IDP FOR VERIFICATION, callback func. is then ran to get value of user and session");
})
This will process all the requests before they are forwarded to the routes later.
A middleware needs to be set on router object if you are using express js
router.use(isUserAuthenticated)
Don't forget to put this on the top of your routes file.
See the difference between app level and router level middleware here
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 a Jade file that all of my templates extend called layout.jade. In it I want to be able to have a logout button if the user is currently logged in (this is kept track of in req.session).
So layout.jade will have something like,
-if (loggedin)
a.navButton(href="/logout") Log Out
The route for a page would look something like,
app.get("/foo", function(req, res) {
res.render("foo", {loggedin: req.session.isValidUser});
});
The thing is, I don't want to have to populate the loggedin variable manually in every single route. Is there a way I can use Express middleware to automatically set some default options for the object sent to res.render? Or is there a better method to do this?
Basically I'm asking how I can have some set of variables always sent to templates, as well as the ability to have certain custom variables available in certain templates by manually setting them in the routes.
It seems this is actually a documented feature I just had trouble finding, unless anyone has a better way of doing it; From the latest Express documentation,
app.locals: Application local variables are provided to all templates
rendered within the application. This is useful for providing helper
functions to templates, as well as app-level data.
So in my login success function has,
req.session.username = profile.username;
app.locals.username = profile.username;
My logout function,
app.get('/logout', function (req, res) {
delete app.locals.username;
req.session.destroy();
res.redirect('/login');
});
And finally in layout.jade/all of my templates,
- if(username)
a.navButton(href="/logout") Logout
If you set res.locals.loggedin in the /login route, as hexacyanide suggests, this local will not be available in the route for /foo. res.locals is cleared upon every request.
you could instead try placing this above other routes:
app.all('*', function(req, res, next){
if(req.user){
res.locals.loggedin = true;
res.locals.currentuser = req.user;
};
next();
});
Pretty sure that if you modify req.user during your route, the res.locals.currentuser that you set before won't updated to be the new req.user. but not certain about that.
I actually use a custom render function for each page where I render a template, it looks like this:
function myRender(templateName){
return function(req, res){
res.locals.currentuser = req.user || null;
res.render(templateName);
};
};
and I use it like this:
app.get('/foo'
, function(req, res, next){
res.locals.bar = req.query['bar'] || "";
console.log('passing request to myRender middleware');
next();
}
, myRender('foo-jade-template')
)
This has the advantage of only setting res.locals.currentuser when I am ready to render something, instead of before executing my route. So if I change req.user it is guranteed to have the most recent version at render time.
There is a line of code that is rather useful to you in the Express source:
// merge res.locals
options._locals = self.locals;
Therefore, when you run res.render(), Express will also take any locals that are stored in res.locals and pass them into the render. Therefore, all you have to do is set res.locals.loggedin to true, and then run res.render() as usual.
app.get('/login', function(res, res) {
res.locals.loggedin = true;
});
app.get('/foo', function(req, res) {
res.render('foo', {});
});