路由在 Express 中执行"/>
异步中间件被跳过,下一个路由在 Express 中执行
我正在尝试使用 express.js 实现类似 zotero 的应用程序,但我遇到了问题。
我实际上并不知道到底是什么问题,但是根据我得到的日志,我知道我的中间件不知何故没有按照它们设置的顺序执行,而且请求泄漏到我设置的另一个路由处理程序中错误。
这是我的收藏路线处理程序:
router
.route('/')
.post(
controller.addLibraryToBody,
controller.validateBody.create,
controller.createOne,
controller.sendResponse('create'),
controller.debugLog
);
这些是中间件:
// in the parent Controller class
moveReqKeyToBody(bodyKey: string, ...nestedReqKey: string[]) {
return function (req: IRequest, res: Response, next: NextFunction) {
let iterator: any = req;
nestedReqKey.forEach(key => {
if (iterator[key]) iterator = iterator[key];
else
next(createError(400, `missing item from request: ${nestedReqKey}`));
});
req.body[bodyKey] = iterator;
next();
};
}
createOne = catchAsync(
async (
req: IRemoveFieldsRequest,
res: Response,
next: NextFunction
): Promise<void> => {
const document = await this.model.create(req.body);
if (req.removeFields) {
req.removeFields.forEach(field => {
document[field] = undefined;
});
}
req[this.modelName] = document;
next();
}
);
sendResponse = (operation: CRUD) => {
return (req: IRequest, res: Response, next: NextFunction) => {
switch (operation) {
case 'create':
res.status(201).json({
status: 'success',
data: req[this.modelName]
});
break;
}
};
};
debugLog(req: IRequest, res: Response, next: NextFunction) {
console.log(
`${Date.now()} - ${req.url} - ParamKeys: ${Object.keys(
req.params
)} - BodyKeys: ${Object.keys(req.body)}`
);
next();
}
// in the CollectionController
addLibraryToBody = this.moveReqKeyToBody('parent', 'library', 'id');
validateBody = {
create: catchAsync(
async (req: IRequest, res: Response, next: NextFunction) => {
if (!req.body.type) req.body.type = collectionTypes.collection;
this.preventMaliciousBody(this.bodyKeys.create)(req, res, next);
if (
req.body.type === collectionTypes.searchingCollection &&
!req.body.searchQuery
)
next(createError(400, 'invalid body'));
else next();
}
)
}
这是我的 app.js:
app
.use('/api', apiRouter)
.use(
'*',
function (req: Request, res: Response, next: NextFunction) {
// todo fix this weird bug
if (res.headersSent) {
console.log(req.url);
console.log(req.body);
console.log(req.params);
} else next();
},
Controller.unavailable
)
.use(errorHandler);
这是邮递员在那条路线上的输出:
{
"status": "success"
}
这是服务器的 cli 输出: 我正在运行摩根中间件(第一行)
POST /api/libraries/6447a4c4dc088d6d43204668/collections 201 6.358 ms - 20
1683371139354 - / - ParamKeys: id - BodyKeys: name,parent,type
/
{
name: 'norma coll',
parent: '6447a4c4dc088d6d43204668',
type: 'Collection'
}
{ '0': '/api/libraries/6447a4c4dc088d6d43204668/collections' }
我尝试记录所有内容,并在网上搜索但不明白出了什么问题。
编辑:我在
console.log
之后的createOne
方法中添加了一个req[this.modelName] = document
:
createOne = catchAsync(
async (
req: IRemoveFieldsRequest,
res: Response,
next: NextFunction
): Promise<void> => {
const document = await this.model.create(req.body);
if (req.removeFields) {
req.removeFields.forEach(field => {
document[field] = undefined;
});
}
req[this.modelName] = document;
console.log('created');
next();
}
);
而且是在morgan的日志之后打印的:
POST /api/libraries/6447a4c4dc088d6d43204668/collections 201 42.222 ms - 20
created
1683386485926 - / - ParamKeys: id - BodyKeys: name,parent,type
/
{
name: 'normal coll',
parent: '6447a4c4dc088d6d43204668',
type: 'Collection'
}
{ '0': '/api/libraries/6447a4c4dc088d6d43204668/collections' }
所以我猜这里有问题?也许它最后执行并因此调用下一个中间件?
回答如下:看来主要控制问题在
validateBody.create()
。你正在执行:
this.preventMaliciousBody(this.bodyKeys.create)(req, res, next);
但是,假设它是同步的,因为你在它之后继续执行。相反,直到它在其实现内部调用
next()
才完成。您可以像这样使用嵌套中间件,方法是发送您自己的 next 回调而不是实际的 next。这样,您可以在调用回调时看到实际完成的时间。
validateBody = {
create: catchAsync(
async (req: IRequest, res: Response, next: NextFunction) => {
if (!req.body.type) req.body.type = collectionTypes.collection;
this.preventMaliciousBody(this.bodyKeys.create)(req, res, (err) => {
if (err) {
next(err);
return;
}
if (
req.body.type === collectionTypes.searchingCollection &&
!req.body.searchQuery
) {
next(createError(400, 'invalid body'));
} else {
next();
}
}));
}
)
}
moveReqKeyToBody()
中也有几个编码错误。
在
.forEach()
中,您可以多次调用 next(createError(400, ...));
,然后在 .forEach()
循环之后调用 next()
。您需要对其进行编码,以便 next(...)
只被调用一次。
虽然我真的不知道这个功能应该做什么,或者如果这完全是你问的问题的原因,你可以从解决上述两个问题开始:
// in the parent Controller class
moveReqKeyToBody(bodyKey: string, ...nestedReqKey: string[]) {
return function (req: IRequest, res: Response, next: NextFunction) {
let iterator: any = req;
for (let key: any of nestedReqKey) {
if (iterator[key]) {
iterator = iterator[key];
} else {
next(createError(400, `missing item from request: ${nestedReqKey}`));
return;
}
}
req.body[bodyKey] = iterator;
next();
};
}
我还注意到,如果开关操作不是
sendResponse()
,create
不会做任何事情。您至少应该有一个 default
臂连接到发送响应或触发错误的开关。如果您总是期望参数是create
,那么您甚至不需要switch
语句。所以,它应该是一个或另一个。
更多推荐
异步中间件被跳过,下一个路由在 Express 中执行
发布评论