最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

异步中间件被跳过,下一个路由在 Express 中执行

网站源码admin36浏览0评论

异步中间件被跳过,下一个路由在 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
语句。所以,它应该是一个或另一个。

发布评论

评论列表(0)

  1. 暂无评论