摘要:捕捉錯(cuò)誤確保捕獲運(yùn)行路由處理程序和中間件時(shí)發(fā)生的所有錯(cuò)誤非常重要。對(duì)和的調(diào)用表明當(dāng)前處理程序已完成并處于什么狀態(tài),將跳過(guò)鏈中的所有剩余處理程序,除了那些設(shè)置為處理上述錯(cuò)誤的處理程序。
錯(cuò)誤處理
錯(cuò)誤處理是指Express如何捕獲和處理同步和異步發(fā)生的錯(cuò)誤,Express附帶一個(gè)默認(rèn)的錯(cuò)誤處理程序,因此你無(wú)需編寫(xiě)自己的錯(cuò)誤處理程序即可開(kāi)始使用。
捕捉錯(cuò)誤確保Express捕獲運(yùn)行路由處理程序和中間件時(shí)發(fā)生的所有錯(cuò)誤非常重要。
路由處理程序和中間件內(nèi)的同步代碼中發(fā)生的錯(cuò)誤不需要額外的工作,如果同步代碼拋出錯(cuò)誤,則Express將捕獲并處理它,例如:
app.get("/", function (req, res) { throw new Error("BROKEN"); // Express will catch this on its own. });
對(duì)于由路由處理程序和中間件調(diào)用的異步函數(shù)返回的錯(cuò)誤,必須將它們傳遞給next()函數(shù),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); } }); });
如果將任何內(nèi)容傳遞給next()函數(shù)(字符串"route"除外),則Express將當(dāng)前請(qǐng)求視為錯(cuò)誤,并將跳過(guò)任何剩余的非錯(cuò)誤處理路由和中間件函數(shù)。
如果序列中的回調(diào)不提供數(shù)據(jù),只提供錯(cuò)誤,則可以按如下方式簡(jiǎn)化此代碼:
app.get("/", [ function (req, res, next) { fs.writeFile("/inaccessible-path", "data", next); }, function (req, res) { res.send("OK"); } ]);
在上面的示例中,next作為fs.writeFile的回調(diào)提供,調(diào)用時(shí)有或沒(méi)有錯(cuò)誤,如果沒(méi)有錯(cuò)誤,則執(zhí)行第二個(gè)處理程序,否則Express會(huì)捕獲并處理錯(cuò)誤。
你必須捕獲由路由處理程序或中間件調(diào)用的異步代碼中發(fā)生的錯(cuò)誤,并將它們傳遞給Express進(jìn)行處理,例如:
app.get("/", function (req, res, next) { setTimeout(function () { try { throw new Error("BROKEN"); } catch (err) { next(err); } }, 100); });
上面的示例使用try...catch塊來(lái)捕獲異步代碼中的錯(cuò)誤并將它們傳遞給Express,如果省略try...catch塊,Express將不會(huì)捕獲錯(cuò)誤,因?yàn)樗皇峭教幚沓绦虼a的一部分。
使用promises可以避免try...catch塊的開(kāi)銷或者使用返回promises的函數(shù),例如:
app.get("/", function (req, res, next) { Promise.resolve().then(function () { throw new Error("BROKEN"); }).catch(next); // Errors will be passed to Express. });
由于promises會(huì)自動(dòng)捕獲同步錯(cuò)誤和拒絕promises,你可以簡(jiǎn)單地提供next作為最終的catch處理程序,Express將捕獲錯(cuò)誤,因?yàn)?b>catch處理程序被賦予錯(cuò)誤作為第一個(gè)參數(shù)。
你還可以使用處理程序鏈來(lái)依賴同步錯(cuò)誤捕獲,通過(guò)將異步代碼減少為一些簡(jiǎn)單的代碼,例如:
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); } ]);
上面的例子有一些來(lái)自readFile調(diào)用的簡(jiǎn)單語(yǔ)句,如果readFile導(dǎo)致錯(cuò)誤,那么它將錯(cuò)誤傳遞給Express,否則你將快速返回到鏈中下一個(gè)處理程序中的同步錯(cuò)誤處理的世界。然后,上面的示例嘗試處理數(shù)據(jù),如果失敗,則同步錯(cuò)誤處理程序?qū)⒉东@它,如果你在readFile回調(diào)中完成了此處理,則應(yīng)用程序可能會(huì)退出,并且Express錯(cuò)誤處理程序?qū)o(wú)法運(yùn)行。
無(wú)論使用哪種方法,如果要調(diào)用Express錯(cuò)誤處理程序并使應(yīng)用程序存活,你必須確保Express收到錯(cuò)誤。
默認(rèn)錯(cuò)誤處理程序Express附帶了一個(gè)內(nèi)置的錯(cuò)誤處理程序,可以處理應(yīng)用程序中可能遇到的任何錯(cuò)誤,此默認(rèn)錯(cuò)誤處理中間件函數(shù)添加在中間件函數(shù)堆棧的末尾。
如果你將錯(cuò)誤傳遞給next()并且你沒(méi)有在自定義錯(cuò)誤處理程序中處理它,它將由內(nèi)置錯(cuò)誤處理程序處理,錯(cuò)誤將堆棧跟蹤寫(xiě)入客戶端,堆棧跟蹤不包含在生產(chǎn)環(huán)境中。
將環(huán)境變量NODE_ENV設(shè)置為production,以在生產(chǎn)模式下運(yùn)行應(yīng)用程序。
如果在開(kāi)始寫(xiě)入響應(yīng)后調(diào)用next()并出現(xiàn)錯(cuò)誤(例如,如果在將響應(yīng)流式傳輸?shù)娇蛻舳藭r(shí)遇到錯(cuò)誤),則Express默認(rèn)錯(cuò)誤處理程序?qū)㈥P(guān)閉連接并使請(qǐng)求失敗。
因此,當(dāng)你添加自定義錯(cuò)誤處理程序時(shí),必須在headers已發(fā)送到客戶端時(shí)委托給默認(rèn)的Express錯(cuò)誤處理程序:
function errorHandler (err, req, res, next) { if (res.headersSent) { return next(err) } res.status(500) res.render("error", { error: err }) }
請(qǐng)注意,如果你在你的代碼調(diào)用next()出現(xiàn)錯(cuò)誤多次,則會(huì)觸發(fā)默認(rèn)錯(cuò)誤處理程序,即使自定義錯(cuò)誤處理中間件已就緒也是如此。
編寫(xiě)錯(cuò)誤處理程序以與其他中間件函數(shù)相同的方式定義錯(cuò)誤處理中間件函數(shù),除了錯(cuò)誤處理函數(shù)有四個(gè)參數(shù)而不是三個(gè):(err, req, res, next),例如:
app.use(function (err, req, res, next) { console.error(err.stack) res.status(500).send("Something broke!") })
你可以在其他app.use()和路由調(diào)用之后定義錯(cuò)誤處理中間件,例如:
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 })
中間件函數(shù)內(nèi)的響應(yīng)可以是任何格式,例如HTML錯(cuò)誤頁(yè)面、簡(jiǎn)單消息或JSON字符串。
對(duì)于組織(和更高級(jí)別的框架)目的,你可以定義多個(gè)錯(cuò)誤處理中間件函數(shù),就像使用常規(guī)中間件函數(shù)一樣,例如,為使用XHR和不使用XHR的請(qǐng)求定義錯(cuò)誤處理程序:
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可能會(huì)將請(qǐng)求和錯(cuò)誤信息寫(xiě)入stderr,例如:
function logErrors (err, req, res, next) { console.error(err.stack) next(err) }
同樣在此示例中,clientErrorHandler定義如下,在這種情況下,錯(cuò)誤會(huì)明確傳遞給下一個(gè)錯(cuò)誤。
請(qǐng)注意,在錯(cuò)誤處理函數(shù)中不調(diào)用“next”時(shí),你負(fù)責(zé)編寫(xiě)(和結(jié)束)響應(yīng),否則這些請(qǐng)求將“掛起”,并且不符合垃圾回收的條件。
function clientErrorHandler (err, req, res, next) { if (req.xhr) { res.status(500).send({ error: "Something failed!" }) } else { next(err) } }
實(shí)現(xiàn)“catch-all”的errorHandler函數(shù),如下所示(例如):
function errorHandler (err, req, res, next) { res.status(500) res.render("error", { error: err }) }
如果你有一個(gè)具有多個(gè)回調(diào)函數(shù)的路由處理程序,則可以使用route參數(shù)跳轉(zhuǎn)到下一個(gè)路由處理程序,例如:
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) }) })
在此示例中,將跳過(guò)getPaidContent處理程序,但app中的/a_route_behind_paywall中的任何剩余處理程序?qū)⒗^續(xù)執(zhí)行。
對(duì)next()和next(err)的調(diào)用表明當(dāng)前處理程序已完成并處于什么狀態(tài),next(err)將跳過(guò)鏈中的所有剩余處理程序,除了那些設(shè)置為處理上述錯(cuò)誤的處理程序。上一篇:使用模板引擎 下一篇:調(diào)試
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/100488.html
摘要:常見(jiàn)問(wèn)題我該如何構(gòu)建我的應(yīng)用程序這個(gè)問(wèn)題沒(méi)有明確的答案,答案取決于你的應(yīng)用程序規(guī)模和所涉及的團(tuán)隊(duì),為了盡可能靈活,在結(jié)構(gòu)方面沒(méi)有做出任何假設(shè)。請(qǐng)參閱,了解以模型為中心的基于的框架。 常見(jiàn)問(wèn)題 我該如何構(gòu)建我的應(yīng)用程序? 這個(gè)問(wèn)題沒(méi)有明確的答案,答案取決于你的應(yīng)用程序規(guī)模和所涉及的團(tuán)隊(duì),為了盡可能靈活,Express在結(jié)構(gòu)方面沒(méi)有做出任何假設(shè)。 在你喜歡的任何目錄結(jié)構(gòu)中,路由和其他特定于...
摘要:調(diào)用堆棧中的下一個(gè)中間件函數(shù)。此示例顯示了一個(gè)中間件子堆棧,它處理對(duì)路徑的請(qǐng)求。要從路由器中間件堆棧跳過(guò)其余的中間件函數(shù),請(qǐng)調(diào)用將控制權(quán)傳遞給下一個(gè)路由,注意僅適用于使用或函數(shù)加載的中間件函數(shù)。 使用中間件 Express是一個(gè)路由和中間件Web框架,其本身的功能非常小:Express應(yīng)用程序本質(zhì)上是一系列中間件函數(shù)調(diào)用。 中間件函數(shù)是可以訪問(wèn)請(qǐng)求對(duì)象(req)、響應(yīng)對(duì)象(res)以及...
摘要:在向頁(yè)面發(fā)送內(nèi)容時(shí),程序也不會(huì)往下執(zhí)行我們也可以裝在一組中間件路由級(jí)中間件路由級(jí)中間件和應(yīng)用級(jí)中間件一樣,只是它綁定的對(duì)象為。安裝所需功能的模塊,并在應(yīng)用中加載,可以在應(yīng)用級(jí)加載,也可以在路由級(jí)加載。 Express 框架 根據(jù)官方的介紹,Express 是一個(gè)基于 Node.js 平臺(tái)的極簡(jiǎn)、靈活的 web 應(yīng)用開(kāi)發(fā)框架,可以輕松的創(chuàng)建各種 web 或者移動(dòng)端應(yīng)用 今天就來(lái)簡(jiǎn)單的了解...
摘要:使用承諾和異步功能來(lái)擺脫回調(diào)地獄的應(yīng)用程序,并簡(jiǎn)化錯(cuò)誤處理。它暴露了自己的和對(duì)象,而不是的和對(duì)象。因此,可被視為的模塊的抽象,其中是的應(yīng)用程序框架。這使得中間件對(duì)于整個(gè)堆棧而言不僅僅是最終應(yīng)用程序代碼,而且更易于書(shū)寫(xiě),并更不容易出錯(cuò)。 Koa 與 Express 此系列文章的應(yīng)用示例已發(fā)布于 GitHub: koa-docs-Zh-CN. 可以 Fork 幫助改進(jìn)或 Star 關(guān)注更新...
摘要:方法此中間件在及更高版本中可用。由于的形狀基于用戶控制的輸入,因此該對(duì)象中的所有屬性和值都是不可信的,應(yīng)該在信任之前進(jìn)行驗(yàn)證。注意為獲得最佳結(jié)果,請(qǐng)使用反向代理緩存來(lái)提高服務(wù)靜態(tài)資源的性能。 express() 創(chuàng)建一個(gè)Express應(yīng)用程序,express()函數(shù)是express模塊??導(dǎo)出的頂級(jí)函數(shù)。 var express = require(express); var app ...
閱讀 594·2021-11-18 13:12
閱讀 1314·2021-11-15 11:39
閱讀 2473·2021-09-23 11:22
閱讀 6194·2021-09-22 15:15
閱讀 3655·2021-09-02 09:54
閱讀 2310·2019-08-30 11:10
閱讀 3245·2019-08-29 14:13
閱讀 2913·2019-08-29 12:49