Express - 在中间件函数之间传递数据的更好模式

时间:2015-12-18 00:49:23

标签: javascript node.js express

我刚用Express提出了这个问题,我对StackOverflow对它的看法很感兴趣:

https://github.com/strongloop/express/issues/2831

我的问题是为什么Express选择禁止开发人员在中间件函数之间直接传递数据,并且基本上强迫您将临时数据分配给请求对象,我一直认为这是非常尴尬的分配

更具体:

在中间件函数之间传递数据通常涉及到这样做

req.specialData = {}
next();
然而,如果可能的话,它可能会更容易和更高效(!)

next(null,data);

function mySpecialMiddleWare(req,res,next,data){}

//现在,调用上面的函数

mySpecialMiddleWare(req,res,next, {some:data});
问题是Express使用a,我认为是愚蠢的方式来确定调用是通常的中间件函数还是下一个错误的第一个中间件函数,通过检查是否function.length> 3或function.length === 4 ...

我说的话有什么可能吗?

不允许通过中间件函数直接传递数据而不是将数据分配给req?更好/更容易/更快/更强?

也许Express已经具备了这种能力,我只是被误导了?

2 个答案:

答案 0 :(得分:7)

  

我的问题是为什么Express选择禁止开发人员直接在中间件函数之间传递数据,并且基本上强迫您将临时数据分配给请求对象,而我一直认为这是一项相当尴尬的任务。

所以我认为API是鼓励大多数中间件模块化,可重用和松散耦合的方式。这意味着通常应该做一些事情,而不必过多关注其他中间件可能在它们之前或之后运行的内容。为了实现这一目标并创建一个松散兼容的中间件功能的生态系统,express使API保持相当通用。这有利有弊。但作为对第一个问题的直接回答,我会说保持界面简单,一致和灵活,并尽量避免严格的排序依赖。

在您的情况下,中间件之间可能存在隐式依赖关系。另一个常见示例通常是您的会话中间件具有您的cookie中间件在其之前运行的隐式依赖。拥有这些都是隐含的可以被认为是创建错误和不必要的故障排除。另一方面,它使应用程序开发人员能够更轻松地混合和匹配可能不会彼此了解的中间件。

事后我认为我和一些快速维护者都会同意,出于语义API的原因,使用函数arity(预期参数的数量)是TJ的一个奇怪和糟糕的选择。我认为如果要重写项目,将为错误处理定义更明确的API。

  

允许通过中间件函数直接传递数据而不是将数据笨拙地分配给req会不会更好/更容易/更快/更强?

更好 - 这是非常有争议和基于意见的。它的简单性有很多可以说的,证据是巨大的生态系统和使用。有其他可用的选择,如hapi,restify等,但你可能会考虑它们。

更容易 - 可能不是。什么是非常容易的。

更快 - 可能没有任何有意义的方式。不确定为什么您认为您的版本会更快,但最好在您提出此类声明时提供指标。

更强 - 如果通过“更强”你的意思更明确,这可能是正确的但是有一些人仍然喜欢JavaScript,即使TypeScript一直通过Haskell存在并且在某种意义上肯定“更强”。< / p>

答案 1 :(得分:3)

Express正在做什么可能有好处,但值得注意的是Express允许使用res.locals在中间件之间传递数据。话虽如此,你的问题激励我创建这个库。 Expressjs-plus. 有了它,您将能够轻松地在中间件之间传递数据,而无需使用请求和响应对象。

您可以使用常规的JavaScript功能,例如函数(varInResLocals,varInReqParams,callback)而不是表达中间件签名。

这是一个适合您的工作示例。

 var express = require('express');
 var ExpressPlus = require('expressjs-plus').ExpressPlus;
 var app = express();
 // simple handler example
 var userHandler = function(param, paramsArray, req, res){
    if(param !== 'user') return false;
    paramsArray.push("USER WAS FOUND!");
    return true;
};

 // this handler allows you to pass res.locals properties between your middlewares seemingly,
 // it the parameter was found in locals, it attaches it to paramsArray.
 var resLocalsHandler = function(param, paramsArray, req, res){
    if(param in res.locals){
        paramsArray.push(res.locals[param]);
        return true;
    }else return false;
};
 var appPlus = new ExpressPlus(app, [userHandler, resLocalsHandler], []);
 var regularFunction = function(user, id, cb){
    return cb(null, { response: {user: user, id: id}, status: 200, resLocalsVar: "passVar" });
};

 // resLocalsVar was passed in a previous method
 var regularFunction2 = function(resLocalsVar, user, id, cb){
 // now you can have access to it
    console.log(resLocalsVar);
    return cb(null);
};

 // the responder at the end will use res.locals.status and res.locals.response to issue an HTTP response
 app.use(appPlus.GMV(regularFunction), appPlus.GMV(regularFunction2), appPlus.responder);

 // adds error handlers, it will add a default error handler along with the list of error handlers passed
 // in this case, no error handlers were passed
 appPlus.setErrorHandlers();

 app.listen(3001, function(){
    console.log('Listening!');
});