我有一个同构反应应用程序,我想以某种方式在快速中间件之间传递状态。
我有以下处理表单提交的快递路线:
export const createPaymentHandler = async (req: Request, res: Response, next: NextFunction) => {
const { field } = req.body;
if (!paymentType) {
res.locals.syncErrors = { field: 'some error.' };
next();
return;
}
try {
const { redirectUrl } = await makeRequest<CreatePaymentRequest, CreatePaymentResponse>({
body: { paymentType },
method: HttpMethod.POST
});
res.redirect(redirectUrl);
} catch (err) {
error(err);
res.locals.serverError = true;
next();
}
};
下一个中间件正在处理渲染。
目前我正在使用res.locals
,是否有更好的方式或公认的模式?
因为你的处理程序是异步的,你需要将err
传递给next
,如下所示:
next(err);
为了让您的中间件处理错误,而不是由默认错误处理程序拾取它,您需要有四个参数:
app.use((err, req, res, next) => {
// handle the error
})
值得注意的是,需要在其他中间件之后指定错误处理程序。对于您的情况,使用正常的“成功”中间件和错误处理程序,而不是将两者合并为一个中间件可能是有意义的。
最后,请记住,将err
作为参数传递特定于错误处理程序。如果您只想将一些数据传递到下一个中间件,可以通过修改req
来实现:
req.x = 'some data'
next()
然后,下一个中间件的req
参数将包含您设置的数据。
进一步阅读:https://expressjs.com/en/guide/using-middleware.html#middleware.error-handling
IMO你的问题更多的是将一些数据传递给下一个中间件。由于渲染逻辑由下一个中间件处理,因此快速路由不应该关注数据的使用方式。你的方法看起来很好。
res.locals
是将数据传递到下一个中间件的推荐方法。来自文档:
此属性对于公开请求级别信息(例如请求路径名,经过身份验证的用户,用户设置等)非常有用。
此外,由于添加的变量将限定为当前请求,因此数据仅可用于当前请求的生命周期。也许您可以设置在state
上添加res.locals
键以存储所有状态变量的约定,但是当前的方法也可以正常工作。
如果它将轻量级信息传递给下一个中间件以进行渲染,那么应用res.locals
就可以了。但是,您可能希望查看自定义error-handling
以获取一般错误,例如内部错误。
请考虑以下错误处理
function notFoundHandler(req, res, next) {
res.status(404).render('notFoundPage', {
error: '404 - not found'
});
}
function badRequestHandler(err, req, res, next) {
res.status(400).render('badRequestPage', {
error: 'Bad request'
});
}
function errorHandler(err, req, res, next) {
res.status(err.status || 500).render('errorPage', {
error: 'Internal server error'
});
}
app.use(notFoundHandler);
app.use(badRequestHandler);
app.use(errorHandler);
现在不是将错误详细信息传递给下一个中间件,而是简单地让它流向错误处理程序,例如
export const createPaymentHandler = async (req: Request, res: Response, next:
NextFunction) => {
const { field } = req.body;
if (!paymentType) {
res.status(400);
return next(); // This will hit the Bad Request handler
}
try {
const { redirectUrl } = await makeRequest < CreatePaymentRequest, CreatePaymentResponse > ({
body: { paymentType },
method: HttpMethod.POST
});
res.redirect(redirectUrl);
} catch (err) {
res.status(500);
return next(err); // This will hit the Error Handler
}
};
res.locals
是将数据传递到当前请求范围内的下一个中间件的标准方法。由于您的用例围绕当前请求,因此这样做是有意义的。
同时,处理错误的标准方法是将错误传递给下一个中间件。
next(err);
然后,您可以从错误处理程序处理错误方案。但是,对于同构反应应用程序,这会使事情变得更难。因此,如果您决定沿着这条路走下去,我建议您通过扩展PaymentError
来使用像Error
这样的自定义错误。由于您已经在使用Typescript,因此更有意义。
但是,当您实际考虑这种情况时,当错误不是请求错误时,从反应应用程序的角度来看,它是渲染的特殊状态/属性。因此,我建议采用以下混合方法。
next(err)
方法。res.locals
方法。在快速中间件之间传递状态的最佳方法是使用对象res.locals
已经做的事情。
你是正确和最好的方式!
可能你需要再次关注the documentation from res.locals
:
来自
res.locals
文件的Citate
res.locals
- 包含作用于request
的响应局部变量的对象,因此仅对在request
/response
循环期间呈现的视图(如果有)可用。否则,此属性与app.locals
相同。此属性对于公开
request-level
信息(例如请求路径名,经过身份验证的用户,用户设置等)非常有用。app.use(function(req, res, next) { res.locals.user = req.user; res.locals.authenticated = ! req.user.anonymous; next(); });
你可以看到 - 他们建议使用这个对象。
你是正确的方式!