简体   繁体   English

Express (Node) - 通过中间件循环发送错误消息的正确方法

[英]Express (Node) - Right way to send error messages through middleware cycle

In express applications, what is the right way to send error messages to views ?在快速应用程序中,向视图发送错误消息的正确方法是什么?

(we assume that the code is synchronous) (我们假设代码是同步的)

Example 1 :示例 1:

// Route
Router.route('/')
  .get(controller.getIndex);

// Controller
Controller.getIndex = function (req, res, next) {
  doSomething(function (err, datas) {
    if (err) { res.locals.err = 'error message'; }
    // ...
  });
  res.render(/* view */);
};

// View 
<p class="error">${ out.global.err }</p>

Here no problem : if there is an error, I store a message in the response and display it in the view.这里没问题:如果出现错误,我会在响应中存储一条消息并将其显示在视图中。

Example 2 :示例 2:

// Route (with multiple middlewares)
Router.route('/')
  .get(firstMiddleware, otherMiddleware/*, otherMiddleware2, etc */, controller.getIndex);

// firstMiddleware (always need to be called)
firstMiddleware = function (req, res, next) {
  doAlsoSomething(function (err, datas) {
    if (err) { res.locals.err = 'error message'; }
    // ...
  });
  next();
};

// otherMiddleware, otherMiddleware2 (need to be called only if no errors)
otherMiddleware = function (req, res, next) {
  next();
};

// Controller (need to be called only if want to display the view)
Controller.getIndex = function (req, res, next) {
  doSomething(function (err, datas) {
    if (err) { res.locals.err = 'error message'; }
    // ...
  });
  res.render(/* view */);
};

// View 
<p class="error">${ out.global.err }</p>

In this example, otherMiddleware will be always called.在此示例中,将始终调用 otherMiddleware。 It is not what I want, it should stop the middlewares cycle in case of errors.这不是我想要的,它应该在出现错误时停止中间件循环。 Then if errors need to be display on the view it should called Controller.getIndex() with error messages like in example 1. If errors have their own views (as 404, 500...), it should not call the Controller.getIndex() , but the appropriate view.然后,如果需要在视图上显示错误,它应该调用Controller.getIndex()并带有示例 1 中的错误消息。如果错误有自己的视图(如 404、500...),则不应调用Controller.getIndex() ,但适当的看法。 In any cases, if an error occurs in otherMiddlewareX, the middlewares "after" (otherMiddlewareX + 1, otherMiddlewareX + 2 ... otherMiddlewareN) should not be called.在任何情况下,如果 otherMiddlewareX 发生错误,则不应调用“after”(otherMiddlewareX + 1, otherMiddlewareX + 2 ... otherMiddlewareN)的中间件。

Anyone can help me to find a "right" way to do that ?任何人都可以帮助我找到一种“正确”的方法来做到这一点?

EDIT : similar problem similar stack overflow question编辑:类似问题类似堆栈溢出问题

Possible answers (i can give example of implementations if necessary) :可能的答案(如有必要,我可以举例说明):

  • Put a condition if (res.locals.err) in each middleware to jump to the next one in case of errors by calling next();在每个中间件中放置一个条件if (res.locals.err)以在错误的情况下通过调用next();跳转到下一个next(); . . That's not very convenient.那不是很方便。
  • Call an error-handling middleware with next('error message');使用next('error message');调用错误处理中间件next('error message'); but it is hard to manage every redirection in one function (this is the solution i use)但是很难在一个函数中管理每个重定向(这是我使用的解决方案)
  • Use next('route');使用next('route'); with a route duplication each time to manage error (similar as error-handling middleware solution).每次都有一个路由重复来管理错误(类似于错误处理中间件解决方案)。
  • Use res.redirect();使用res.redirect(); and flash messages (session, query string, db, cookie...).和 flash 消息(会话、查询字符串、db、cookie...)。 If I use this solution, I need to make it stateless.如果我使用这个解决方案,我需要让它无状态。 I could do it with query string for example, but this is also not very convenient to me.例如,我可以使用查询字符串来完成,但这对我来说也不是很方便。 Furthermore, it doesn't really answer the question directly but more the question how to pass message between requests in REST API .此外,它并没有真正直接回答问题,而是更多地回答了如何在 REST API 中的请求之间传递消息的问题。

There is probably a way to do that easily with express app, but I can't arrive to figure out what's the right way.使用 express 应用程序可能有一种方法可以轻松做到这一点,但我无法弄清楚什么是正确的方法。 Could you please help me ?请你帮助我好吗 ?

Thank you in advance.先感谢您。

EDIT : More details about possible answers (third solution).编辑:有关可能答案的更多详细信息(第三种解决方案)。

With next('error message');随着next('error message'); I have an error-handler middleware where I need to display the good view.我有一个错误处理程序中间件,我需要在其中显示好的视图。 The view can be a 500, 404, 406... but also a 200 with an error message on it.视图可以是 500、404、406……但也可以是带有错误消息的 200。 Firstly, I need to give the status code to this middleware, then if it's a 200 I need to call the view that corresponds to the error.首先,我需要给这个中间件提供状态码,然后如果是 200 我需要调用对应于错误的视图。 The problem is that I don't always know which view to call.问题是我并不总是知道要调用哪个视图。 I can have a POST on /auth that needs to be redirected to GET /login.我可以在 /auth 上有一个需要重定向到 GET /login 的 POST。 I need to "hardcode" it and can't write the same code for every situations or i need to pass the view/controller in each next('error message');我需要“硬编码”它并且不能为每种情况编写相同的代码,或者我需要在每个next('error message');传递视图/控制器next('error message'); call.称呼。 Even the redirection is hard, because sometimes I need to call a controller, but sometimes I needs to go through another middleware cycle by calling the route, not the controller and the only way I found is return app._router.handle(req, res, next);即使重定向也很难,因为有时我需要调用一个控制器,但有时我需要通过调用路由而不是控制器来经历另一个中间件循环,我找到的唯一方法是return app._router.handle(req, res, next); which looks more as a "hack" that an official solution.这看起来更像是官方解决方案的“黑客”。 If i redirect with res.redirect();如果我用 res.redirect() 重定向; i came back to my second possible answer where i need to pass some flash messages.我回到了我需要传递一些闪现信息的第二个可能的答案。 To finish, this is the solution i use ( next(err) ), but i was hoping for a better way.最后,这是我使用的解决方案( next(err) ),但我希望有更好的方法。

I'm not sure if I understood your whole problem but I would use and error handling middleware like this:我不确定我是否理解你的整个问题,但我会使用和错误处理这样的中间件:

 // firstMiddleware var firstMiddleware = function (req, res, next) { doAlsoSomething(function (err, datas) { if (err) { next('error message'); } // ... next(); // If err is true calls renderView }); }; // otherMiddleware var otherMiddleware = function (req, res, next) { // Do stuff only if no error next(); }; // Controller Controller.getIndex = function (req, res, next) { doSomething(function (err, datas) { if (err) { next('error message'); } // ... next(); // If err is true calls renderView }); }; // This middleware runs after next('error message') var handleError = function (err, req, res, next) { res.locals.err = err.message; } // This middleware always runs var renderView = function (req, res, next) { res.render(/* view */); } // Route Router.route('/') .get(firstMiddleware, otherMiddleware/*, otherMiddleware2, etc */, controller.getIndex, handleError, renderView);

If you're only using otherMiddleware once, get rid of it, then move its content to the else block of the previous middleware:如果你只使用otherMiddleware一次,去掉它,然后将它的内容移动到前一个中间件的else块:

 var checkForm = function (req, res, next) { validationResult(function (err, datas) { if (err) { res.locals.err = 'error message'; } else { // Do stuff only if form is valid // otherMiddleware code } // ... }); next(); };

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

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