如何在express.js中制作动态中间件链

2024-02-22

我目前正在开发一个 API 管理器来控制现有 API 的项目。

它包含“之前”和“之后”中间件的列表,这些中间件用于执行安全检查和日志记录等操作。以及一个“服务”中间件,用于向现有 API 发出 http 请求。但问题是我想让中间件的执行顺序是动态的,这意味着我可以加载一些配置文件来更改每次请求到来时中间件的执行顺序。

这是我以前的代码:

'use strict';
// Loading the express library
var express = require('express');
var app = express();

var service = require('./routes/index');


// Testing configurable middleware
var confirguration = {
    before1: {
        priority: 100,
        enable: true
    },
    before2: {
        priority: 80,
        enable: true
    },
    service: {
        priority: 50,
        enable: true
    },
    after1: {
        priority: 30,
        enable: true
    },
    after2: {
        priority: 10,
        enable: true
    }
}

var before1 = require('./example_middleware/before1');
var before2 = require('./example_middleware/before2');
var after1 = require('./example_middleware/after1');
var after2 = require('./example_middleware/after2');
// Fake request to simulate the /service
var fakeRequest = require('./example_middleware/fake_request');

// Function to sort the order of the middleware to be executed
var sortConfig = function(confirguration){
    var sortable = [];
    for (var middleware in confirguration)
        // To make middlewares configurable
        if (confirguration[middleware]['enable'] == true){
            sortable.push([middleware, confirguration[middleware]['priority']]);
        }

    sortable.sort(function(a, b) {return b[1] - a[1]});
    return sortable;
}

// var sortedConfig = [];
var middlewareSet = new Array();
app.use('/test', function(request, response, next){
    var middleware;
    var sortedConfig = sortConfig(confirguration);

    for (var i in sortedConfig){
        switch(sortedConfig[i][0]){
            case 'before1':
                middleware = before1;
                break;
            case 'before2':
                middleware = before2;
                break;
            case 'service':
                middleware = fakeRequest;
                break;
            case 'after1':
                middleware = after1;
                break;
            case 'after2':
                middleware = after2;
                break;
        }


        // console.log(sortedConfig[i][0]);
        // Execute the middleware in expected order
        middlewareSet.push(middleware);
    }
    // request.sortedConfig = sortedConfig;
    console.log(middlewareSet);
    console.log('middleware list sorted');
    next();
});

app.use('/test', middlewareSet);

但我不断收到来自最后一行的 app.use() 的相同错误消息:

app.use() 需要中间件函数

如果我使用它,它会起作用:

app.use('/test', [before1, before2, fakeRequest, after1, after2]);

但它不是动态的,我误解了什么?在express.js 中必须有一种方法可以做到这一点。

提前致谢。

EDIT:我根据Ryan的回答修改了我的代码,代码如下:

var async = require('async');
app.use('/test', configurableMiddleWare);

function configurableMiddleWare(req, res, next) {

    var operations = [];

    var middleware;

    var sortedConfig = sortConfig(confirguration);

   // push each middleware you want to run
    sortedConfig.forEach(function(fn) {

        switch(fn[0]){
            case 'before1':
                middleware = before1;
                break;
            case 'before2':
                middleware = before2;
                break;
            case 'service':
                middleware = fakeRequest;
                break;
            case 'after1':
                middleware = after1;
                break;
            case 'after2':
                middleware = after2;
                break;
        }

        operations.push(middleware); // could use fn.bind(null, req, res) to pass in vars  
    });

    console.log('middleware list sorted');
   // now actually invoke the middleware in series
    async.series(operations, function(err) {
        if(err) {
        // one of the functions passed back an error so handle it here
            return next(err);
        }
      // no errors so pass control back to express
        next();
    });

}

为了确保我在测试中间件中没有犯任何错误,下面是其中之一的示例:

'use strict';

var express = require('express');
var router = express.Router();

router.route('/')
    .all(function(request, response, next){
        console.log('This is middleware BEFORE1');
        next();
    });


module.exports = router;

现在,当我运行我的应用程序时,我从 npm 收到以下错误:

类型错误:无法调用未定义的方法“indexOf”

在 Function.proto.handle (/Users/jialunliu/Documents/SOA_project/FAT-LADY/node_modules/express/lib/router/index.js:130:28) 在路由器(/Users/jialunliu/Documents/SOA_project/FAT-LADY/node_modules/express/lib/router/index.js:35:12) 在/Users/jialunliu/Documents/SOA_project/FAT-LADY/node_modules/async/lib/async.js:610:21 在/Users/jialunliu/Documents/SOA_project/FAT-LADY/node_modules/async/lib/async.js:249:17 在迭代(/Users/jialunliu/Documents/SOA_project/FAT-LADY/node_modules/async/lib/async.js:149:13) 在 async.eachSeries (/Users/jialunliu/Documents/SOA_project/FAT-LADY/node_modules/async/lib/async.js:165:9) 在 _asyncMap (/Users/jialunliu/Documents/SOA_project/FAT-LADY/node_modules/async/lib/async.js:248:13) 在Object.mapSeries(/Users/jialunliu/Documents/SOA_project/FAT-LADY/node_modules/async/lib/async.js:231:23) 在 Object.async.series (/Users/jialunliu/Documents/SOA_project/FAT-LADY/node_modules/async/lib/async.js:608:19) 在可配置中间件(/Users/jialunliu/Documents/SOA_project/FAT-LADY/app.js:135:11)

这是来自线路的async.series(operations, function(err){})

我不断收到这种错误消息,说该函数无法从该函数“操作”数组中读取......


我认为你走在正确的轨道上,你只需要调整一些东西。我会注册一个顶级函数app.use()然后在该函数中执行所有动态操作。更新我对工作示例的回答。确保先安装 asyncnpm install --save async

// define all middleware functions
var middleware = {
    mw1: function(req, res, next) {
        console.log('mw 1');
        next();
    },
    mw2: function(req, res, next) {
        console.log('mw 2');
        next();
    },
    mw3: function(req, res, next) {
        console.log('mw 3');
        next();
    },
    mw4: function(req, res, next) {
        console.log('mw 4');
        next();
    }

};

// register our "top level function"
app.use(configurableMiddleware);
var requestCount = 1; // this is just for the working example

function configurableMiddleware(req, res, next) {
    var isEvenRequest = requestCount++ % 2 === 0; // simple logic to alternate which "configurable" middleware to use

    var operations; // in the real world you could build this array dynamically, for now we just hardcode two scenarios as an example

    // Each request to http://localhost:3000 will alternate which middleware is used, so you will see a different log each time
    if(isEvenRequest) {
        console.log('Even request should log mw2 and mw4');
        // .bind(null, req, res) makes sure that the middleware gets the request and response objects when they are invoked, 
        // as of this point they still haven't been invoked...
        operations = [middleware.mw2.bind(null, req, res), middleware.mw4.bind(null, req, res)];
    }
    else {
        console.log('Odd request should log mw1 and mw3');
        operations = [middleware.mw1.bind(null, req, res), middleware.mw3.bind(null, req, res)];
    }

    // invoke each middleware in series - you could also do async.parallel if the order of middleware doesn't matter
    // using the async module: https://github.com/caolan/async
    async.series(operations, function(err) {
        if(err) {
            console.log('There was a problem running the middleware!');
            return next(err);
        }
        // all middleware has been run
        next();
    });
}

有关 .bind() 的更多信息,请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在express.js中制作动态中间件链 的相关文章

随机推荐