自定义中间件express.js框架排序

时间:2020-10-23 12:45:21

标签: node.js express middleware

我正在编写自定义中间件,以在每次请求时将请求数据(例如请求路径,响应代码,请求时间戳等)发送到远程服务器。我无法弄清楚中间件的顺序。

我已经创建了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();
}

我的路线/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;

1 个答案:

答案 0 :(得分:2)

如评论中所述,对中间件进行抽象处理,以避免在每个路由上定义一组中间件。

要替换m1,请创建一个全局中间件,在所有其他中间件之前定义全局中间件,该中间件将res.on("finish", function () {})事件处理程序设置为在路由完成后执行某些操作。我很确定这是唯一的事件,如果您在任何地方进行res.statusCode都将获得实际正确的res.status()

然后将404错误处理程序逻辑移到主错误处理程序中,然后可以在登录和响应之前检查状态代码和所有有用的东西。您还可以使用req.xhr来确定如何响应。

此外,您可以使用包罗万象的方法来获取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!')
})