在同构反应应用程序中的快速中间件之间传递状态

问题描述 投票:8回答:5

我有一个同构反应应用程序,我想以某种方式在快速中间件之间传递状态。

我有以下处理表单提交的快递路线:

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,是否有更好的方式或公认的模式?

javascript node.js reactjs express
5个回答
2
投票

因为你的处理程序是异步的,你需要将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


2
投票

IMO你的问题更多的是将一些数据传递给下一个中间件。由于渲染逻辑由下一个中间件处理,因此快速路由不应该关注数据的使用方式。你的方法看起来很好。

res.locals是将数据传递到下一个中​​间件的推荐方法。来自文档:

此属性对于公开请求级别信息(例如请求路径名,经过身份验证的用户,用户设置等)非常有用。

此外,由于添加的变量将限定为当前请求,因此数据仅可用于当前请求的生命周期。也许您可以设置在state上添加res.locals键以存储所有状态变量的约定,但是当前的方法也可以正常工作。


2
投票

如果它将轻量级信息传递给下一个中间件以进行渲染,那么应用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
    }
};

2
投票

res.locals是将数据传递到当前请求范围内的下一个中间件的标准方法。由于您的用例围绕当前请求,因此这样做是有意义的。

同时,处理错误的标准方法是将错误传递给下一个中间件。

next(err);

然后,您可以从错误处理程序处理错误方案。但是,对于同构反应应用程序,这会使事情变得更难。因此,如果您决定沿着这条路走下去,我建议您通过扩展PaymentError来使用像Error这样的自定义错误。由于您已经在使用Typescript,因此更有意义。

但是,当您实际考虑这种情况时,当错误不是请求错误时,从反应应用程序的角度来看,它是渲染的特殊状态/属性。因此,我建议采用以下混合方法。

  1. 如果错误具有高优先级,即,如果错误应该停止呈现预期内容并回退到特殊页面,请使用next(err)方法。
  2. 如果错误应该只是状态报告的一部分,那么使用res.locals方法。

1
投票

在快速中间件之间传递状态的最佳方法是使用对象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();
});

你可以看到 - 他们建议使用这个对象。

你是正确的方式!

© www.soinside.com 2019 - 2024. All rights reserved.