【问题标题】:pass state around between express middleware in an isomorphic react app在同构反应应用程序中的快速中间件之间传递状态
【发布时间】:2019-01-22 14:04:21
【问题描述】:

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

我有以下处理表单提交的快速路由:

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

【问题讨论】:

  • 不是专家,但在异步方法中,您可以将错误/错误作为文本文件写入文件夹。同时,您将在 Node 中设置一个事件侦听器来查看此文件夹,这将由文件夹状态更改时的操作系统..

标签: javascript node.js reactjs express


【解决方案1】:

因为您的处理程序是异步的,您需要将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 是将数据传递给下一个中间件的推荐方式。来自文档:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        next(err);
        

        然后您可以从错误处理程序处理错误场景。然而,对于一个同构的 react 应用程序,这会使事情变得更加困难。因此,如果您决定走这条路,我建议您通过扩展 Error 来使用像 PaymentError 这样的自定义错误。这会更有意义,因为您已经在使用 Typescript。

        但是,当你真正考虑这个场景时,当错误不是请求错误时,从 react 应用的角度来看,它是一种特殊的渲染状态/属性。因此,我建议采用以下混合方法。

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

        【讨论】:

          【解决方案5】:

          在 express 中间件之间传递状态的最佳方式是使用对象 res.locals 你已经做了什么。

          你是在正确和最好的方式!

          您可能需要再次查看the documentation from res.locals

          引用res.locals的文档

          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();
          });
          

          你可以看到——他们推荐使用这个对象。

          你是在正确的方式!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-04-18
            • 1970-01-01
            • 1970-01-01
            • 2010-09-12
            • 2022-01-15
            • 1970-01-01
            • 1970-01-01
            • 2016-08-09
            相关资源
            最近更新 更多