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

IT技术 javascript node.js reactjs express
2021-05-11 12:11:03

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

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

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

4个回答

因为您的处理程序是异步的,所以您需要传递errinto 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 您的问题更多是关于将一​​些数据传递给下一个中间件。由于渲染逻辑由下一个中间件处理,因此 express 路由不应该关心数据的使用方式。你的方法看起来不错。

res.locals是将数据传递给下一个中间件的推荐方式。从文档:

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

此外,由于添加的变量将作用于当前请求,因此数据仅适用于当前请求的生命周期。也许您可以设置在 上添加一个stateres.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);

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

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

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