自定义中间件 express.js 框架排序
Custom middleware express.js framework ordering
我正在编写自定义中间件以在每次请求时将请求数据(如请求路径、响应代码、请求时间戳等)发送到远程服务器。我无法确定我的中间件的顺序。
我创建了2个中间件,
a) process_request (m1) --> 这个中间件只是向请求对象添加一个时间戳,以便在收到请求时进行注册。
b) process_response (m2) --> 这个中间件将需要的数据发布到远程服务器
m1
function process_request(req, res, next) {
req.requestTime = Date.now()/1000;
next();
}
平方米
function process_response(req, res, next) {
const request_obj = {};
request_obj.request_timestamp = req.requestTime;
request_obj.response_timestamp = Date.now()/1000;
request_obj.path = req.protocol + "://" +
req.get('host') + req.originalUrl;
request_obj.response_code = res.statusCode;
send_perf_request(request_obj); // sends remote https request not shown here
}
我可以在 app.js
中想到两个订购选项:
订单 1:
m1
route 1
route 2
...
route n
m2
404 request handler middleware
订单 2:
m1
route 1
route 2
...
route n
404 request handler middleware
m2
404请求处理器中间件
app.use((req, res, next) => {
const err = new Error('Not Found');
err.status = 404;
next(err);
});
order 1
的问题是我无法捕获我想要的 404 请求。
order 2
在所有请求中的问题 responseCode=404
因为 404 请求处理程序中间件正在这样做。
我是 node.js 的新手,如果我以正确的方式思考这个问题,我会感到困惑。
我的app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const custom_middleware = require("custom_middleware");
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(custom_middleware.process_request); //*calling middleware
app.use('/', indexRouter);
app.use('/users', usersRouter);
//catch 404 and forward to error handler
// app.use(function(req, res, next) {
// console.log("in 404 handler");
// //next(createError(404, "this page doesn't exist;"));
// next();
// });
// error handler
app.use(function(err, req, res, next) {
// this is called only in case of errors
// set locals, only providing error in development
console.log("in error handler");
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
console.log(res.statusCode);
//res.render('error');
next(err);
});
app.use(custom_middleware.process_exception); //*calling middleware
module.exports = app;
自定义中间件文件
function process_request(req, res, next) {
// this middleware adds request timestamp
console.log("in process request middleware");
req.requestTime = Date.now()/1000;
res.on("finish", function (){
// this middleware collects performance data
console.log("in process response middleware");
const request_obj = {};
request_obj.request_timestamp = req.requestTime;
request_obj.response_timestamp = Date.now()/1000;
request_obj.ip_address = ip.address();
request_obj.path = req.protocol + "://" +
req.get('host') + req.originalUrl;
request_obj.requester = null;
request_obj.response_code = res.statusCode;
console.log(request_obj.response_code);
send_perf_request(request_obj);
})
next();
}
function process_exception(err, req, res, next) {
// this middleware collects exception data
console.log("in process exception middleware");
const error_obj = {};
error_obj.path = req.protocol + "://" +
req.hostname + req.originalUrl;
error_obj.exception = "error occured";
error_obj.traceback = err.stack;
error_obj.user = null;
error_obj.ip_address = ip.address();
send_exception_request(error_obj);
next();
}
我的routes/index.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
throw new Error('this does not exist'); // error manually triggered
res.status(500);
});
module.exports = router;
如评论中所述,将中间件抽象化,以避免在每个路由上定义一组中间件。
替换 m1
创建一个全局中间件,您在所有其他中间件之前定义它,它设置 res.on("finish", function () {})
事件处理程序在路由完成时执行某些操作。我很确定这是唯一一个你会得到实际正确 res.statusCode
如果你在任何地方做 res.status()
的事件。
然后将您的 404 错误处理程序逻辑移动到主错误处理程序中,然后您可以在记录和响应之前检查状态代码和所有有用的东西。您还可以使用 req.xhr 来确定如何响应。
此外,您可以使用 catch-all 在 404 路由上接听:app.get('*', function (req, res, next) {
然后触发错误处理程序处理的错误。
这是一个将所有内容放在一起的示例:
const express = require('express')
const app = express()
// logger middleware
app.use((req, res, next) => {
// set something
req.requestTime = Date.now() / 1000;
// gets fired after all routes have been handled
res.on("finish", function () {
//
req.finishTime = Date.now() / 1000;
// do something with req, res objects
console.log('[in logger] originalUrl:', req.originalUrl)
console.log('[in logger] status code:', res.statusCode)
})
next()
})
// apply routes
// ...
app.get('/', (req, res, next) => {
try {
// example: look for something, which is not found
const mock = false
if (!mock) {
let err = new Error('Mock was not found!')
err.status = 404
throw err
}
res.send('Hello World!')
} catch (err) {
next(err)
}
})
// app.get('/foo', ...
// not found route (catch all)
app.get('*', (req, res, next) => {
let err = new Error('Page not found!')
err.status = 404
next(err)
})
// error handler (will catch everything even uncaught exceptions)
app.use((error, req, res, next) => {
//
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate')
res.header('Expires', '-1')
res.header('Pragma', 'no-cache')
// set status from error
res.status(error.status || 500)
if (req.xhr) {
// is ajax call, send error as json
res.json({
error: error.name || 'Server error',
status: error.status || 500,
message: error.message || 'Internal server error'
})
} else {
// render a view instead (would need to add a view engine)
res.render('error/' + (error.status || 500), error)
}
})
app.listen(3000, function () {
console.log('App listening on port 3000!')
})
我正在编写自定义中间件以在每次请求时将请求数据(如请求路径、响应代码、请求时间戳等)发送到远程服务器。我无法确定我的中间件的顺序。
我创建了2个中间件,
a) process_request (m1) --> 这个中间件只是向请求对象添加一个时间戳,以便在收到请求时进行注册。
b) process_response (m2) --> 这个中间件将需要的数据发布到远程服务器
m1
function process_request(req, res, next) {
req.requestTime = Date.now()/1000;
next();
}
平方米
function process_response(req, res, next) {
const request_obj = {};
request_obj.request_timestamp = req.requestTime;
request_obj.response_timestamp = Date.now()/1000;
request_obj.path = req.protocol + "://" +
req.get('host') + req.originalUrl;
request_obj.response_code = res.statusCode;
send_perf_request(request_obj); // sends remote https request not shown here
}
我可以在 app.js
中想到两个订购选项:
订单 1:
m1
route 1
route 2
...
route n
m2
404 request handler middleware
订单 2:
m1
route 1
route 2
...
route n
404 request handler middleware
m2
404请求处理器中间件
app.use((req, res, next) => {
const err = new Error('Not Found');
err.status = 404;
next(err);
});
order 1
的问题是我无法捕获我想要的 404 请求。
order 2
在所有请求中的问题 responseCode=404
因为 404 请求处理程序中间件正在这样做。
我是 node.js 的新手,如果我以正确的方式思考这个问题,我会感到困惑。
我的app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const custom_middleware = require("custom_middleware");
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(custom_middleware.process_request); //*calling middleware
app.use('/', indexRouter);
app.use('/users', usersRouter);
//catch 404 and forward to error handler
// app.use(function(req, res, next) {
// console.log("in 404 handler");
// //next(createError(404, "this page doesn't exist;"));
// next();
// });
// error handler
app.use(function(err, req, res, next) {
// this is called only in case of errors
// set locals, only providing error in development
console.log("in error handler");
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
console.log(res.statusCode);
//res.render('error');
next(err);
});
app.use(custom_middleware.process_exception); //*calling middleware
module.exports = app;
自定义中间件文件
function process_request(req, res, next) {
// this middleware adds request timestamp
console.log("in process request middleware");
req.requestTime = Date.now()/1000;
res.on("finish", function (){
// this middleware collects performance data
console.log("in process response middleware");
const request_obj = {};
request_obj.request_timestamp = req.requestTime;
request_obj.response_timestamp = Date.now()/1000;
request_obj.ip_address = ip.address();
request_obj.path = req.protocol + "://" +
req.get('host') + req.originalUrl;
request_obj.requester = null;
request_obj.response_code = res.statusCode;
console.log(request_obj.response_code);
send_perf_request(request_obj);
})
next();
}
function process_exception(err, req, res, next) {
// this middleware collects exception data
console.log("in process exception middleware");
const error_obj = {};
error_obj.path = req.protocol + "://" +
req.hostname + req.originalUrl;
error_obj.exception = "error occured";
error_obj.traceback = err.stack;
error_obj.user = null;
error_obj.ip_address = ip.address();
send_exception_request(error_obj);
next();
}
我的routes/index.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
throw new Error('this does not exist'); // error manually triggered
res.status(500);
});
module.exports = router;
如评论中所述,将中间件抽象化,以避免在每个路由上定义一组中间件。
替换 m1
创建一个全局中间件,您在所有其他中间件之前定义它,它设置 res.on("finish", function () {})
事件处理程序在路由完成时执行某些操作。我很确定这是唯一一个你会得到实际正确 res.statusCode
如果你在任何地方做 res.status()
的事件。
然后将您的 404 错误处理程序逻辑移动到主错误处理程序中,然后您可以在记录和响应之前检查状态代码和所有有用的东西。您还可以使用 req.xhr 来确定如何响应。
此外,您可以使用 catch-all 在 404 路由上接听:app.get('*', function (req, res, next) {
然后触发错误处理程序处理的错误。
这是一个将所有内容放在一起的示例:
const express = require('express')
const app = express()
// logger middleware
app.use((req, res, next) => {
// set something
req.requestTime = Date.now() / 1000;
// gets fired after all routes have been handled
res.on("finish", function () {
//
req.finishTime = Date.now() / 1000;
// do something with req, res objects
console.log('[in logger] originalUrl:', req.originalUrl)
console.log('[in logger] status code:', res.statusCode)
})
next()
})
// apply routes
// ...
app.get('/', (req, res, next) => {
try {
// example: look for something, which is not found
const mock = false
if (!mock) {
let err = new Error('Mock was not found!')
err.status = 404
throw err
}
res.send('Hello World!')
} catch (err) {
next(err)
}
})
// app.get('/foo', ...
// not found route (catch all)
app.get('*', (req, res, next) => {
let err = new Error('Page not found!')
err.status = 404
next(err)
})
// error handler (will catch everything even uncaught exceptions)
app.use((error, req, res, next) => {
//
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate')
res.header('Expires', '-1')
res.header('Pragma', 'no-cache')
// set status from error
res.status(error.status || 500)
if (req.xhr) {
// is ajax call, send error as json
res.json({
error: error.name || 'Server error',
status: error.status || 500,
message: error.message || 'Internal server error'
})
} else {
// render a view instead (would need to add a view engine)
res.render('error/' + (error.status || 500), error)
}
})
app.listen(3000, function () {
console.log('App listening on port 3000!')
})