摘要:捕捉错误确保捕获运行路由处理程序和中间件时发生的所有错误非常重要。对和的调用表明当前处理程序已完成并处于什么状态,将跳过链中的所有剩余处理程序,除了那些设置为处理上述错误的处理程序。
错误处理
错误处理是指Express如何捕获和处理同步和异步发生的错误,Express附带一个默认的错误处理程序,因此你无需编写自己的错误处理程序即可开始使用。
捕捉错误确保Express捕获运行路由处理程序和中间件时发生的所有错误非常重要。
路由处理程序和中间件内的同步代码中发生的错误不需要额外的工作,如果同步代码抛出错误,则Express将捕获并处理它,例如:
app.get("/", function (req, res) { throw new Error("BROKEN"); // Express will catch this on its own. });
对于由路由处理程序和中间件调用的异步函数返回的错误,必须将它们传递给next()函数,Express将捕获并处理它们,例如:
app.get("/", function (req, res, next) { fs.readFile("/file-does-not-exist", function (err, data) { if (err) { next(err); // Pass errors to Express. } else { res.send(data); } }); });
如果将任何内容传递给next()函数(字符串"route"除外),则Express将当前请求视为错误,并将跳过任何剩余的非错误处理路由和中间件函数。
如果序列中的回调不提供数据,只提供错误,则可以按如下方式简化此代码:
app.get("/", [ function (req, res, next) { fs.writeFile("/inaccessible-path", "data", next); }, function (req, res) { res.send("OK"); } ]);
在上面的示例中,next作为fs.writeFile的回调提供,调用时有或没有错误,如果没有错误,则执行第二个处理程序,否则Express会捕获并处理错误。
你必须捕获由路由处理程序或中间件调用的异步代码中发生的错误,并将它们传递给Express进行处理,例如:
app.get("/", function (req, res, next) { setTimeout(function () { try { throw new Error("BROKEN"); } catch (err) { next(err); } }, 100); });
上面的示例使用try...catch块来捕获异步代码中的错误并将它们传递给Express,如果省略try...catch块,Express将不会捕获错误,因为它不是同步处理程序代码的一部分。
使用promises可以避免try...catch块的开销或者使用返回promises的函数,例如:
app.get("/", function (req, res, next) { Promise.resolve().then(function () { throw new Error("BROKEN"); }).catch(next); // Errors will be passed to Express. });
由于promises会自动捕获同步错误和拒绝promises,你可以简单地提供next作为最终的catch处理程序,Express将捕获错误,因为catch处理程序被赋予错误作为第一个参数。
你还可以使用处理程序链来依赖同步错误捕获,通过将异步代码减少为一些简单的代码,例如:
app.get("/", [ function (req, res, next) { fs.readFile("/maybe-valid-file", "utf8", function (err, data) { res.locals.data = data; next(err); }); }, function (req, res) { res.locals.data = res.locals.data.split(",")[1]; res.send(res.locals.data); } ]);
上面的例子有一些来自readFile调用的简单语句,如果readFile导致错误,那么它将错误传递给Express,否则你将快速返回到链中下一个处理程序中的同步错误处理的世界。然后,上面的示例尝试处理数据,如果失败,则同步错误处理程序将捕获它,如果你在readFile回调中完成了此处理,则应用程序可能会退出,并且Express错误处理程序将无法运行。
无论使用哪种方法,如果要调用Express错误处理程序并使应用程序存活,你必须确保Express收到错误。
默认错误处理程序Express附带了一个内置的错误处理程序,可以处理应用程序中可能遇到的任何错误,此默认错误处理中间件函数添加在中间件函数堆栈的末尾。
如果你将错误传递给next()并且你没有在自定义错误处理程序中处理它,它将由内置错误处理程序处理,错误将堆栈跟踪写入客户端,堆栈跟踪不包含在生产环境中。
将环境变量NODE_ENV设置为production,以在生产模式下运行应用程序。
如果在开始写入响应后调用next()并出现错误(例如,如果在将响应流式传输到客户端时遇到错误),则Express默认错误处理程序将关闭连接并使请求失败。
因此,当你添加自定义错误处理程序时,必须在headers已发送到客户端时委托给默认的Express错误处理程序:
function errorHandler (err, req, res, next) { if (res.headersSent) { return next(err) } res.status(500) res.render("error", { error: err }) }
请注意,如果你在你的代码调用next()出现错误多次,则会触发默认错误处理程序,即使自定义错误处理中间件已就绪也是如此。
编写错误处理程序以与其他中间件函数相同的方式定义错误处理中间件函数,除了错误处理函数有四个参数而不是三个:(err, req, res, next),例如:
app.use(function (err, req, res, next) { console.error(err.stack) res.status(500).send("Something broke!") })
你可以在其他app.use()和路由调用之后定义错误处理中间件,例如:
var bodyParser = require("body-parser") var methodOverride = require("method-override") app.use(bodyParser.urlencoded({ extended: true })) app.use(bodyParser.json()) app.use(methodOverride()) app.use(function (err, req, res, next) { // logic })
中间件函数内的响应可以是任何格式,例如HTML错误页面、简单消息或JSON字符串。
对于组织(和更高级别的框架)目的,你可以定义多个错误处理中间件函数,就像使用常规中间件函数一样,例如,为使用XHR和不使用XHR的请求定义错误处理程序:
var bodyParser = require("body-parser") var methodOverride = require("method-override") app.use(bodyParser.urlencoded({ extended: true })) app.use(bodyParser.json()) app.use(methodOverride()) app.use(logErrors) app.use(clientErrorHandler) app.use(errorHandler)
在此示例中,通用logErrors可能会将请求和错误信息写入stderr,例如:
function logErrors (err, req, res, next) { console.error(err.stack) next(err) }
同样在此示例中,clientErrorHandler定义如下,在这种情况下,错误会明确传递给下一个错误。
请注意,在错误处理函数中不调用“next”时,你负责编写(和结束)响应,否则这些请求将“挂起”,并且不符合垃圾回收的条件。
function clientErrorHandler (err, req, res, next) { if (req.xhr) { res.status(500).send({ error: "Something failed!" }) } else { next(err) } }
实现“catch-all”的errorHandler函数,如下所示(例如):
function errorHandler (err, req, res, next) { res.status(500) res.render("error", { error: err }) }
如果你有一个具有多个回调函数的路由处理程序,则可以使用route参数跳转到下一个路由处理程序,例如:
app.get("/a_route_behind_paywall", function checkIfPaidSubscriber (req, res, next) { if (!req.user.hasPaid) { // continue handling this request next("route") } else{ next(); } }, function getPaidContent (req, res, next) { PaidContent.find(function (err, doc) { if (err) return next(err) res.json(doc) }) })
在此示例中,将跳过getPaidContent处理程序,但app中的/a_route_behind_paywall中的任何剩余处理程序将继续执行。
对next()和next(err)的调用表明当前处理程序已完成并处于什么状态,next(err)将跳过链中的所有剩余处理程序,除了那些设置为处理上述错误的处理程序。上一篇:使用模板引擎 下一篇:调试
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/100488.html
摘要:常见问题我该如何构建我的应用程序这个问题没有明确的答案,答案取决于你的应用程序规模和所涉及的团队,为了尽可能灵活,在结构方面没有做出任何假设。请参阅,了解以模型为中心的基于的框架。 常见问题 我该如何构建我的应用程序? 这个问题没有明确的答案,答案取决于你的应用程序规模和所涉及的团队,为了尽可能灵活,Express在结构方面没有做出任何假设。 在你喜欢的任何目录结构中,路由和其他特定于...
摘要:调用堆栈中的下一个中间件函数。此示例显示了一个中间件子堆栈,它处理对路径的请求。要从路由器中间件堆栈跳过其余的中间件函数,请调用将控制权传递给下一个路由,注意仅适用于使用或函数加载的中间件函数。 使用中间件 Express是一个路由和中间件Web框架,其本身的功能非常小:Express应用程序本质上是一系列中间件函数调用。 中间件函数是可以访问请求对象(req)、响应对象(res)以及...
摘要:在向页面发送内容时,程序也不会往下执行我们也可以装在一组中间件路由级中间件路由级中间件和应用级中间件一样,只是它绑定的对象为。安装所需功能的模块,并在应用中加载,可以在应用级加载,也可以在路由级加载。 Express 框架 根据官方的介绍,Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,可以轻松的创建各种 web 或者移动端应用 今天就来简单的了解...
摘要:使用承诺和异步功能来摆脱回调地狱的应用程序,并简化错误处理。它暴露了自己的和对象,而不是的和对象。因此,可被视为的模块的抽象,其中是的应用程序框架。这使得中间件对于整个堆栈而言不仅仅是最终应用程序代码,而且更易于书写,并更不容易出错。 Koa 与 Express 此系列文章的应用示例已发布于 GitHub: koa-docs-Zh-CN. 可以 Fork 帮助改进或 Star 关注更新...
摘要:方法此中间件在及更高版本中可用。由于的形状基于用户控制的输入,因此该对象中的所有属性和值都是不可信的,应该在信任之前进行验证。注意为获得最佳结果,请使用反向代理缓存来提高服务静态资源的性能。 express() 创建一个Express应用程序,express()函数是express模块导出的顶级函数。 var express = require(express); var app ...
阅读 567·2021-11-18 13:12
阅读 1266·2021-11-15 11:39
阅读 2444·2021-09-23 11:22
阅读 6084·2021-09-22 15:15
阅读 3619·2021-09-02 09:54
阅读 2280·2019-08-30 11:10
阅读 3204·2019-08-29 14:13
阅读 2888·2019-08-29 12:49