Promise 和 EventEmitter 之间的 ExpressJS 明显竞争条件
ExpressJS apparent race condition between Promise and EventEmitter
我有一个 NodeJS/Express 网络应用程序,允许用户上传文件,然后我使用 connect-busboy save to my database using Sequelize 解析该文件。完成后,我想将用户重定向到给定页面。但是 Express 在我的 Promise 解决之前返回了 404 状态,即使我从未调用 next()
,我 认为 是强制性的,以便调用下一个处理程序中间件链,从而导致 404.
到目前为止,这是我的代码:
function uploadFormFile(req, res, next) {
var documentInstanceID = req.params.documentInstanceID;
// set up an object to hold my data
var data = {
file: null,
documentDate: null,
mimeType: null
};
// call the busboy middleware explicitly
// EDIT: this turned out to be the problem... of course this calls next()
// removing this line and moving it to an app.use() made everything work as expected
busboy(req, res, next);
req.pipe(req.busboy);
req.busboy.on('file', function (fieldName, file, fileName, encoding, mimeType) {
var fileData = [];
data.mimeType = mimeType;
file.on('data', function (chunk) {
fileData.push(chunk);
});
file.on('end', function () {
data.file = Buffer.concat(fileData);
});
});
req.busboy.on('finish', function () {
// api methods return promises from Sequelize
api.querySingle('DocumentInstance', ['Definition'], null, { DocumentInstanceID: documentInstanceID })
.then(function (documentInstance) {
documentInstance.RawFileData = data.file;
documentInstance.FileMimeType = data.mimeType;
// chaining promise
return api.save(documentInstance);
}).then(function () {
res.redirect('/app/page');
});
});
}
我可以确认我的数据已正确保存。但是由于竞争条件,由于 Express 返回 404 状态,网页显示“不能 POST”,并且 res.redirect
失败并设置 headers 错误因为它在发送 404 后尝试重定向。
谁能帮我弄清楚为什么 Express 返回 404?
问题出在处理程序中对 busboy 的内部调用。它不是执行并简单地将控制权返回给您的处理程序,而是调用 returns 控制之前传递给它的 next
。所以你在 busboy 调用确实执行后编写代码,但请求已经超过了那个点。
如果您希望某些中间件只针对某些请求执行,您可以将中间件链接到这些请求中,例如:
router.post('/upload',busboy,uploadFromFile)
也可以用.use()
分隔,如:
router.use('/upload', busboy);
router.post('/upload', uploadFromFile);
以上任何一个都将按照您预期的方式链接中间件。在 .use()
的情况下,中间件也将应用于任何适用的 .METHOD()
,因为 Express 在其文档中引用了它。
另请注意,您可以通过这种方式传入任意数量的中间件,作为单独的参数或作为中间件函数的数组,例如:
router.post('/example', preflightCheck, logSomeStuff, theMainHandler);
// or
router.post('example', [ preflightCheck,logSomeStuff ], theMainHandler);
上述任一示例的执行行为都是等效的。仅代表我自己,并不建议这是最佳实践,如果我在运行时构建中间件列表,我通常只使用基于数组的中间件添加。
祝你好运。希望您和我一样喜欢使用 Express。
我有一个 NodeJS/Express 网络应用程序,允许用户上传文件,然后我使用 connect-busboy save to my database using Sequelize 解析该文件。完成后,我想将用户重定向到给定页面。但是 Express 在我的 Promise 解决之前返回了 404 状态,即使我从未调用 next()
,我 认为 是强制性的,以便调用下一个处理程序中间件链,从而导致 404.
到目前为止,这是我的代码:
function uploadFormFile(req, res, next) {
var documentInstanceID = req.params.documentInstanceID;
// set up an object to hold my data
var data = {
file: null,
documentDate: null,
mimeType: null
};
// call the busboy middleware explicitly
// EDIT: this turned out to be the problem... of course this calls next()
// removing this line and moving it to an app.use() made everything work as expected
busboy(req, res, next);
req.pipe(req.busboy);
req.busboy.on('file', function (fieldName, file, fileName, encoding, mimeType) {
var fileData = [];
data.mimeType = mimeType;
file.on('data', function (chunk) {
fileData.push(chunk);
});
file.on('end', function () {
data.file = Buffer.concat(fileData);
});
});
req.busboy.on('finish', function () {
// api methods return promises from Sequelize
api.querySingle('DocumentInstance', ['Definition'], null, { DocumentInstanceID: documentInstanceID })
.then(function (documentInstance) {
documentInstance.RawFileData = data.file;
documentInstance.FileMimeType = data.mimeType;
// chaining promise
return api.save(documentInstance);
}).then(function () {
res.redirect('/app/page');
});
});
}
我可以确认我的数据已正确保存。但是由于竞争条件,由于 Express 返回 404 状态,网页显示“不能 POST”,并且 res.redirect
失败并设置 headers 错误因为它在发送 404 后尝试重定向。
谁能帮我弄清楚为什么 Express 返回 404?
问题出在处理程序中对 busboy 的内部调用。它不是执行并简单地将控制权返回给您的处理程序,而是调用 returns 控制之前传递给它的 next
。所以你在 busboy 调用确实执行后编写代码,但请求已经超过了那个点。
如果您希望某些中间件只针对某些请求执行,您可以将中间件链接到这些请求中,例如:
router.post('/upload',busboy,uploadFromFile)
也可以用.use()
分隔,如:
router.use('/upload', busboy);
router.post('/upload', uploadFromFile);
以上任何一个都将按照您预期的方式链接中间件。在 .use()
的情况下,中间件也将应用于任何适用的 .METHOD()
,因为 Express 在其文档中引用了它。
另请注意,您可以通过这种方式传入任意数量的中间件,作为单独的参数或作为中间件函数的数组,例如:
router.post('/example', preflightCheck, logSomeStuff, theMainHandler);
// or
router.post('example', [ preflightCheck,logSomeStuff ], theMainHandler);
上述任一示例的执行行为都是等效的。仅代表我自己,并不建议这是最佳实践,如果我在运行时构建中间件列表,我通常只使用基于数组的中间件添加。
祝你好运。希望您和我一样喜欢使用 Express。