Express/Connect:调用redis后无法解析正文
我试图通过基于请求的路径仅调用某些中间件函数来缩短Express/Connect中间件管道 但是,以下操作将失败:Express/Connect:调用redis后无法解析正文,express,connect,middleware,Express,Connect,Middleware,我试图通过基于请求的路径仅调用某些中间件函数来缩短Express/Connect中间件管道 但是,以下操作将失败: _cookieParser(req, res, function(err) { if(err) return next(err); _session(req, res, function(err) { if(err) return next(err); _csrf(req, res, function(err) {
_cookieParser(req, res, function(err) {
if(err) return next(err);
_session(req, res, function(err) {
if(err) return next(err);
_csrf(req, res, function(err) {
if(err) return next(err);
loadUserFromSession(req, res, function(err) {
if(err) return next(err);
if(req.method == "POST") {
_bodyParser(req, res, next);
} else {
next();
}
});
});
});
});
但这很好:
_cookieParser(req, res, function(err) {
if(err) return next(err);
_session(req, res, function(err) {
if(err) return next(err);
_csrf(req, res, function(err) {
if(err) return next(err);
_bodyParser(req, res, function(err) {
if(err) return next(err);
loadUserFromSession(req, res, next);
});
});
});
});
其中loadUserFromSession是:
function loadUserFromSession(req, res, next) {
if(req.session && req.session.userId) {
userFunctions.getUserById(req.session.userId, function(err, user) {
if(err) return next(err);
if(user) {
req.user = user;
return next();
} else {
req.session.destroy();
return next(new Error('Unauthenticated'));
}
});
} else {
return next(new Error('Unauthenticated'));
}
};
为什么我不能在loadUserFromSession()之后调用bodyParser()
编辑
很抱歉,缺少有关失败/意外结果的详细信息
如果在loadUserFromSession()之后放置bodyParser()或json()(因为POST内容是json),则调用永远不会在json()内部返回。如果我在节点检查器中的res.on('data')或res.on('end')上放置断点,则两者都不会被触发
json中间件的来源如下:
exports = module.exports = function(options){
var options = options || {}
, strict = options.strict !== false;
var limit = options.limit
? _limit(options.limit)
: noop;
return function json(req, res, next) {
if (req._body) return next();
req.body = req.body || {};
if (!utils.hasBody(req)) return next();
// check Content-Type
if ('application/json' != utils.mime(req)) return next();
// flag as parsed
req._body = true;
// parse
limit(req, res, function(err){
if (err) return next(err);
var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){
buf += chunk <==BREAKPOINT NEVER GETS CALLED
});
req.on('end', function(){
var first = buf.trim()[0]; <==BREAKPOINT NEVER GETS CALLED
if (0 == buf.length) {
return next(400, 'invalid json, empty body');
}
if (strict && '{' != first && '[' != first) return next(400, 'invalid json');
try {
req.body = JSON.parse(buf, options.reviver);
next();
} catch (err){
err.body = buf;
err.status = 400;
next(err);
}
});
});
}
};
exports=module.exports=function(选项){
var options=options | |{}
,strict=options.strict!==false;
var limit=选项。限制
?_限制(选项限制)
:noop;
返回函数json(req、res、next){
如果(请求_body)返回next();
req.body=req.body | |{};
如果(!utils.hasBody(req))返回next();
//检查内容类型
if('application/json'!=utils.mime(req))返回next();
//标记为已解析
要求_body=true;
//解析
限制(请求、恢复、功能(错误){
if(err)返回next(err);
var buf='';
请求设置编码('utf8');
请求on('data',函数(块){
Buf+= Cux OK,考虑这个建议/代码审查,而不是一个具体的答案,但希望这有帮助。
首先,我想理解以下内容将解决您的问题并取消您的确认,尽管我无法确切说明上面的第二个示例与第一个示例的行为不同的原因,但请根据这些信息进行一些实验:对于给定的请求,一系列事件(
数据
、结束
等)将触发一次且仅触发一次。如果侦听器在触发时未连接,则该侦听器永远不会被调用。如果侦听器在触发后连接,则永远不会被调用。bodyParser
具有避免多次尝试重新解析同一请求正文的代码(因为必要的事件永远不会触发,代码将在不响应请求的情况下挂起)
因此,我怀疑您的应用程序中有app.use(express.bodyParser())
,并且中间件在您的上述自定义内容之前被调用并运行。因此,我的建议(也解决了您的文件上载安全问题)是:
不要像您在示例中看到的那样全局安装bodyParser
:app.use(express.bodyParser())
。此代码适用于第一天的示例应用程序,但完全不适用于生产站点。您应该改为执行以下操作:
app.post('/upload/some/file', express.bodyParser(), myUploadHandler);
只需在需要的地方使用body解析器,而不必在其他地方使用。不要再深入到奇怪的nesty中间件堆栈中。有一些干净的方法可以获得所需的功能、安全性和效率,这些功能、安全性和效率与connect内置的中间件堆栈设计相协调。一般来说,请理解您可以使用不同的中间件可以将不同路径上的软件堆栈和express/connect配置为与您希望在一个路径一个路径的基础上发生的事情很好地匹配。请编辑您的问题并替换为“将失败”如果故障不是错误,则使用实际错误消息和堆栈跟踪或描述错误行为。附带注释,使用中间件的方法较少。对于express(礼貌地说),上面的内容是不符合规范的。请尝试app.use('/some/path',someMiddleware)
如果您只想在某些路径中使用某些东西,但实际上大多数中间件在不应用于当前请求时的成本非常小。例如,bodyParser只需检查请求方法并调用next()
如果没有正文,请立即执行。这不是一个你不应该尝试解决的问题。@PeterLyons添加了关于我问题的更多细节。在结构上,我一点也不同意你的看法。我走这条路,不是因为性能,而是安全性。我不想让我的应用程序上载所有可能发布的文件。我有一些端点是公开的,有些不是。我不想让我的应用程序过载(或者DDOS,如果知道的话)。我不想让人们将文件上传到不允许上传的端点。这是我第一次尝试的;我希望避免在每个路由上都有2/3/4个中间件调用,特别是在它们重复的情况下;因此我的方法如上所述。