I'd like to use a app.use:
app.use(function(req, res, next){
console.log('%s %s', req.method, req.url);
next();
});
But it only works if I have no app.get or app.post in my code, if I have one my app.use is ignore.
I'd like to execute a script each time a app.get or a app.use is called
I also try:
app.use(function(req, res, next){
console.log('%s %s', req.method, req.url);
app.get('/',function(req,res){console.log('aa')})
next();
});
in this case my app.get is ignore
Thanks for your help
you have to put your app.use() above the router. The router is usually inside the express configuration so just put your app.use() above the configuration. Something like this:
app.use(function(req, res, next) {
console.log('awesome');
next();
})
app.configure(function(){
// config
app.use(app.router);
});
Also have a look at the build in logger.
Related
I'm building a example website using Express and I hit something I don't quite understand.
Error-handling middleware(s) should be last one(s) in the pipeline, if I understand correctly. For example, works just fine:
var http = require('http');
var express = require('express');
var app = express();
app.set('view engine', 'jade');
app.set('views', './views');
app.use(express.static('./public'));
http.createServer(app).listen(portNumber, function() { });
app.get('/hello', function(req, res) {
res.send('Welcome!');
});
app.use(function(err, req, res, next) {
res.status(500).send('something broke!');
});
app.get('/error', function(req, res, next) {
somethingNonExistent(2016);
});
However, if I register that middleware before http.createServer call, but after all other middlewares were registered, it won't work - my code isn't called:
var http = require('http');
var express = require('express');
var app = express();
app.use(express.static('./public'));
app.use(function(err, req, res, next) {
res.status(500).send('something broke!');
});
http.createServer(app).listen(portNumber, function() { });
app.get('/hello', function(req, res) {
res.send('Welcome!');
});
app.get('/error', function(req, res, next) {
somethingNonExistent(2016);
});
What did I miss here? My guess is that app.get calls use some middleware internally and it gets messed up. I use Express 3.2.6 and Node.js 0.10.29, if that makes any difference
When you define routes/middleware, the path you specify is used to see if it matches with incoming requests. Your request will always be routed to the first match. A request might have multiple matches, so order matters here. You can hit the next matching route/middleware by calling the next() function.
When you mount middleware using app.use without specifying a path, every path is eligible to hit that middleware. So, if it's the first thing you mount, every request will use that middleware.
If you want a catch all error handler, you'll want the opposite - you should mount middleware at the very end of your route definitions. You'll need to call the next function in your handler to actually reach this middleware:
app.get('/hello', function(req, res, next) {
...
// Let's pretend that there was some error
next()
});
// After all of your route definitions...
app.use(function(req, res) {
res.status(500).send('something broke!');
})
Note that if no route exists for the current path, you will also hit this catch all middleware.
Docs
http://expressjs.com/en/guide/error-handling.html
You define error-handling middleware last, after other app.use() and
routes calls; for example:
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
app.use(bodyParser());
app.use(methodOverride());
app.use(function(err, req, res, next) {
// logic
});
The Internal
For ease of understanding, you can imagine the pipeline. When your controller receives a request, inside Express, it looks like this
try {
fn(req, res, next); // your controller
} catch (err) {
next(err);
}
So, then your code throw error, it will call next with err. Basically, it's the same as call next(new Error()). After that, express trying to find next middleware with 4 arguments in middleware pipeline. In your situation error handler declared before your shady controller, so he doesn't involved.
Technically, there is no difference between the controller and middlewares. Optionally you can pass in the controller next parameter , and call it to pass through the pipeline further. If you don't call next(), you finish processing the request.
I have the following in app.js:
app.use(express.static(path.join(__dirname, 'public')));
app.use(function(req, res, next) {
console.log('app.use');
...
next();
});
app.use(app.router);
public folder have subfolder images, css and js.
After app.use(app.router);, I have route definition for returning an image from Amazon S3.
app.get('/images/:type/:id', image);
The problem is that when a page contain image, app.use was called twice. How to prevent it? I want to ignore /images/* calling app.use(function(req, res, next) {});
In general Express uses middleware connect architecture. Every middleware accepts next function which if is called passes the flow to the next middleware. So, in theory if you miss it you could archive what you want:
app.use(function(req, res, next) {
// check if the route matches amazon file
if(...amazon file...) {
// serve image
} else {
next();
}
});
app.use(express.static(path.join(__dirname, 'public')));
As far as I can tell I'm configuring my global middleware function as described in the docs and in every forum post on the subject, but it is not being called. Does anyone see what I'm doing wrong? express 3.2.5. In the log output I see the following:
Express server listening on port 9000
inside route
GET / 200 7ms - 2b
I expect to see "inside middleware", then "inside route". Instead, I just see "inside route".
The code:
var express = require('express'), http=require('http'), path=require('path');
var app = express();
app.enable('trust proxy');
app.set('port', process.env.PORT || 9000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.set('layout', 'layout');
app.use(require('express-ejs-layouts'));
app.use(express.favicon(__dirname + '/public/images/favicon.ico'));
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride())
app.use(express.cookieParser('kfiwknks'));
app.use(express.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
if ('development' == app.get('env')) {
app.use(express.errorHandler());
} else {
app.use(function(err, req, res, next){
console.error (error);
res.send (500, "Internal server error");
});
}
app.use (function (req, res, next) {
console.log ("inside middleware");
next();
});
app.get ("/", function (req, res) {
console.log ("inside route");
res.send(200);
});
http.createServer(app).listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'));
});
This related post:
Express 3 error middleware not being called
is specific to error handling middleware. Mine is a vanilla middleware.
You should put your middleware before you use app.router.
...
app.use (function (req, res, next) {
console.log ("inside middleware");
next();
});
...
app.use(app.router);
Updated answer for Express 4 users from the Express 4 docs. See example from docs below. Note that app.router is deprecated and no longer used. I also added a dummy route to make the ordering clear.
You define error-handling middleware last, after other app.use() and routes calls
Example:
var bodyParser = require('body-parser');
app.use(bodyParser());
app.get('/', function(req, res) {
res.send('hello world');
})
app.use(function(err, req, res, next) {
// logic
});
I'm trying to build a web server in node.js that will support cross-domain scripting, while still providing static files from a public directory. I'm using the express.js and am not really sure how to allow cross-domain scripting (Access-Control-Allow-Origin: *).
I saw this post, which I did not find helpful.
var express = require('express')
, app = express.createServer();
app.get('/', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
app.configure(function () {
app.use(express.methodOverride());
app.use(express.bodyParser());
app.use(app.router);
});
app.configure('development', function () {
app.use(express.static(__dirname + '/public'));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function () {
var oneYear = 31557600000;
// app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
app.use(express.static(__dirname + '/public'));
app.use(express.errorHandler());
});
app.listen(8888);
console.log('express running at http://localhost:%d', 8888);
Check out the example from enable-cors.org:
In your ExpressJS app on node.js, do the following with your routes:
app.all('/', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
app.get('/', function(req, res, next) {
// Handle the get for this route
});
app.post('/', function(req, res, next) {
// Handle the post for this route
});
The first call (app.all) should be made before all the other routes in your app (or at least the ones you want to be CORS enabled).
[Edit]
If you want the headers to show up for static files as well, try this (make sure it's before the call to use(express.static()):
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
I tested this with your code, and got the headers on assets from the public directory:
var express = require('express')
, app = express.createServer();
app.configure(function () {
app.use(express.methodOverride());
app.use(express.bodyParser());
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
app.use(app.router);
});
app.configure('development', function () {
app.use(express.static(__dirname + '/public'));
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function () {
app.use(express.static(__dirname + '/public'));
app.use(express.errorHandler());
});
app.listen(8888);
console.log('express running at http://localhost:%d', 8888);
You could, of course, package the function up into a module so you can do something like
// cors.js
module.exports = function() {
return function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
};
}
// server.js
cors = require('./cors');
app.use(cors());
Following #Michelle Tilley solution, apparently it didn't work for me at first. Not sure why, maybe I am using chrome and different version of node. After did some minor tweaks, it is working for me now.
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
In case someone facing similar issue as mine, this might be helpful.
Try to this cors npm modules.
var cors = require('cors')
var app = express()
app.use(cors())
This module provides many features to fine tune cors setting such as domain whitelisting, enabling cors for specific apis etc.
I use this:
var app = express();
app
.use(function(req, res, next){
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'X-Requested-With');
next();
})
.options('*', function(req, res, next){
res.end();
})
;
h.readFiles('controllers').forEach(function(file){
require('./controllers/' + file)(app);
})
;
app.listen(port);
console.log('server listening on port ' + port);
this code assumes that your controllers are located in the controllers directory. each file in this directory should be something like this:
module.exports = function(app){
app.get('/', function(req, res, next){
res.end('hi');
});
}
Recommend using the cors express module. This allows you to whitelist domains, allow/restrict domains specifically to routes, etc.,
You must set Access-Control-Allow-Credentials: true, if you want to use "cookie" via "Credentials"
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
app.use(function(req, res, next) {
var allowedOrigins = [
"http://localhost:4200"
];
var origin = req.headers.origin;
console.log(origin)
console.log(allowedOrigins.indexOf(origin) > -1)
// Website you wish to allow to
if (allowedOrigins.indexOf(origin) > -1) {
res.setHeader("Access-Control-Allow-Origin", origin);
}
// res.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");
// Request methods you wish to allow
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, OPTIONS, PUT, PATCH, DELETE"
);
// Request headers you wish to allow
res.setHeader(
"Access-Control-Allow-Headers",
"X-Requested-With,content-type,Authorization"
);
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader("Access-Control-Allow-Credentials", true);
// Pass to next layer of middleware
next();
});
Add this code in your index.js or server.js file and change the allowed origin array according to your requirement.
One additional step I needed to take was to switch my URL from http://localhost to http://127.0.0.0
I have some code that looks like the following:
app.configure(function() {
app.set("views", __dirname + "/views");
app.set("view engine", "ejs");
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.logger());
app.use(app.router);
app.use(express.static(__dirname + "/public"));
});
//Routes
app.get("/", function(req, res) {
res.render("index.ejs", {locals: {
title: "Welcome"
}});
});
//Handle 404
app.get("/*", function(req, res, next) {
next("Could not find page");
});
The problem I have is that I can't access anything in the /public static directory: everything gets caught by the 404 route. Am I missing something about how this is supposed to work?
You're doing
app.use(app.router);
app.use(express.static(__dirname + "/public"));
What you want to do is
app.use(express.static(__dirname + "/public"));
app.use(app.router);
Since you have a catch all route in app.router it must be lower then anything else. otherwise the catch all route will indeed catch everything and the rest of the middleware is ignored.
As an aside catch all routes like that are bad.
A better solution would be to place the following code after all calls to app.use:
app.use(function(req, res) {
res.send(404, 'Page not found');
});
Or a similar function.
Do this instead of using app.get("/*", ...
I'm doing it a slightly different way. If you look at the middleware code for the static file server it allows for a callback function that gets called with errors. Only catch is you need the response object to send something useful back to the server. So I do the following:
var errMsgs = { "404": "Dang that file is missing" };
app.use(function(req, res, next){
express.static.send(req, res, next, {
root: __dirname + "/public",
path: req.url,
getOnly: true,
callback: function(err) {
console.log(err);
var code = err.status || 404,
msg = errMsgs["" + code] || "All is not right in the world";
res.render("error", { code: code, msg: msg, layout: false});
}
});
});
Basically what happens is if there is an error it renders my pretty error page and logs something so that I can debug somewhere.