简体   繁体   English

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

[英]pass state around between express middleware in an isomorphic react app

I have an isomorphic react app and I would like to somehow pass state between express middleware. 我有一个同构反应应用程序,我想以某种方式在快速中间件之间传递状态。

I have the following express route that handles form submission: 我有以下处理表单提交的快递路线:

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

The next middleware is handling the rendering. 下一个中间件正在处理渲染。

At the moment I am using res.locals , is there a better way or a recognised pattern? 目前我正在使用res.locals ,是否有更好的方法或公认的模式?

Because your handler is async, you need to pass the err into next , like so: 因为你的处理程序是异步的,你需要将err传递给next ,如下所示:

next(err);

In order for your middleware to process the error, instead of it being picked up by the default error handler, you need to have four parameters: 为了让您的中间件处理错误,而不是由默认错误处理程序拾取它,您需要有四个参数:

app.use((err, req, res, next) => {
  // handle the error
})

It's also worth noting that error handlers need to be specified after other middleware. 值得注意的是,需要在其他中间件之后指定错误处理程序。 For your case, it might make sense to use a normal "success" middleware alongside an error handler, rather than combining the two into one middleware. 对于您的情况,使用正常的“成功”中间件和错误处理程序,而不是将两者合并为一个中间件可能是有意义的。

Finally, keep in mind that passing err as a parameter is specific to error handlers. 最后,请记住,将err作为参数传递特定于错误处理程序。 If you just want to pass some data into your next middleware, you would do that by modifying the req : 如果您只想将一些数据传递到下一个中​​间件,可以通过修改req

req.x = 'some data'
next()

Then, the next middleware's req parameter will have the data you set. 然后,下一个中间件的req参数将包含您设置的数据。


Further reading: https://expressjs.com/en/guide/using-middleware.html#middleware.error-handling 进一步阅读: https//expressjs.com/en/guide/using-middleware.html#middleware.error-handling

IMO your question is more about passing some data to the next middleware. IMO你的问题更多的是将一些数据传递给下一个中间件。 Since the rendering logic is handled by the next middleware, the express route shouldn't be concerned by how the data is being used. 由于渲染逻辑由下一个中间件处理,因此快速路由不应该关注数据的使用方式。 Your approach looks fine. 你的方法看起来很好。

res.locals is the recommended way of passing data to the next middleware. res.locals是将数据传递给下一个中间件的推荐方法。 From the docs: 来自文档:

This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on. 此属性对于公开请求级别信息(例如请求路径名,经过身份验证的用户,用户设置等)非常有用。

Also, since the variables added will be scoped to the current request, thus the data will only be available for the current request's lifecycle. 此外,由于添加的变量将限定为当前请求,因此数据仅可用于当前请求的生命周期。 Perhaps you can set a convention of adding a state key on the res.locals to store all your state variables, but the current approach would also work fine. 也许您可以设置在res.locals上添加state键以存储所有状态变量的res.locals ,但是当前的方法也可以正常工作。

If it's passing lightweight information to the next middleware for rendering purposes then applying res.locals is fine. 如果它将轻量级信息传递给下一个中间件以进行渲染,那么应用res.locals就可以了。 However, you might want to look into custom error-handling for general errors, such as internal error. 但是,您可能希望查看一般错误的自定义error-handling ,例如内部错误。

Consider the following 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);

Now instead of passing error details to the next middleware you would simple let it flow to the error handlers, eg 现在,不要将错误细节传递给下一个中间件,而是简单地让它流向错误处理程序,例如

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 is a standard way to pass data to the next middleware in the scope of the current request. res.locals是将数据传递到当前请求范围内的下一个中间件的标准方法。 Since your use case is around the current request, it makes sense to do so. 由于您的用例围绕当前请求,因此这样做是有意义的。

At the same time, the standard way to handle errors is to pass the error to the next middleware. 同时,处理错误的标准方法是将错误传递给下一个中间件。

next(err);

Then you can handle the error scenario from the error handler. 然后,您可以从错误处理程序处理错误方案。 However, for an isomorphic react app, this would make things harder. 但是,对于同构反应应用程序,这会使事情变得更难。 So if you decide to go down that path, I would suggest you to use a custom error like PaymentError by extending Error . 因此,如果您决定沿着这条路走下去,我建议您通过扩展Error来使用像PaymentError这样的自定义Error This would make even more sense since you are already using Typescript. 由于您已经在使用Typescript,因此更有意义。

However, when you actually think about this scenario, when the error is not a request error, from the point of view of the react app, it is a special state/property of rendering. 但是,当您实际考虑这种情况时,当错误不是请求错误时,从反应应用程序的角度来看,它是渲染的特殊状态/属性。 Thus I suggest the following hybrid approach. 因此,我建议采用以下混合方法。

  1. If the error is of high priority, that is, if the error should stop rendering the expected content and fallback to a special page, use the next(err) approach. 如果错误具有高优先级,即,如果错误应该停止呈现预期内容并回退到特殊页面,请使用next(err)方法。
  2. If the error should just be part of the state report, then use the res.locals approach. 如果错误应该只是状态报告的一部分,那么使用res.locals方法。

The best way to pass a state between express middleware is to use the object res.locals what you already do. 在快速中间件之间传递状态的最佳方法是使用res.locals对象已经执行的操作。

You are on the correct and best way! 你是正确和最好的方式!

May be you have to look to the documentation from res.locals one time again: 您可能需要再次查看res.locals的文档

Citate from documentation of res.locals 从文档Citate res.locals

res.locals – an object that contains response local variables scoped to the request , and therefore available only to the view(s) rendered during that request / response cycle (if any). res.locals - 包含作用于request响应局部变量的对象,因此仅对在request / response周期(如果有)期间呈现的视图可用。 Otherwise, this property is identical to app.locals . 否则,此属性与app.locals相同。

This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on. 此属性对于公开request-level信息(例如请求路径名,经过身份验证的用户,用户设置等)非常有用。

 app.use(function(req, res, next) { res.locals.user = req.user; res.locals.authenticated = ! req.user.anonymous; next(); }); 

And you can see – they recommend to use this object. 你可以看到 - 他们建议使用这个对象。

You are on the right way! 你是正确的方式!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM