摘要:捕捉錯誤確保捕獲運行路由處理程序和中間件時發(fā)生的所有錯誤非常重要。對和的調用表明當前處理程序已完成并處于什么狀態(tài),將跳過鏈中的所有剩余處理程序,除了那些設置為處理上述錯誤的處理程序。
錯誤處理
錯誤處理是指Express如何捕獲和處理同步和異步發(fā)生的錯誤,Express附帶一個默認的錯誤處理程序,因此你無需編寫自己的錯誤處理程序即可開始使用。
捕捉錯誤確保Express捕獲運行路由處理程序和中間件時發(fā)生的所有錯誤非常重要。
路由處理程序和中間件內的同步代碼中發(fā)生的錯誤不需要額外的工作,如果同步代碼拋出錯誤,則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的回調提供,調用時有或沒有錯誤,如果沒有錯誤,則執(zhí)行第二個處理程序,否則Express會捕獲并處理錯誤。
你必須捕獲由路由處理程序或中間件調用的異步代碼中發(fā)生的錯誤,并將它們傳遞給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()并且你沒有在自定義錯誤處理程序中處理它,它將由內置錯誤處理程序處理,錯誤將堆棧跟蹤寫入客戶端,堆棧跟蹤不包含在生產環(huán)境中。
將環(huán)境變量NODE_ENV設置為production,以在生產模式下運行應用程序。
如果在開始寫入響應后調用next()并出現錯誤(例如,如果在將響應流式傳輸到客戶端時遇到錯誤),則Express默認錯誤處理程序將關閉連接并使請求失敗。
因此,當你添加自定義錯誤處理程序時,必須在headers已發(fā)送到客戶端時委托給默認的Express錯誤處理程序:
function errorHandler (err, req, res, next) { if (res.headersSent) { return next(err) } res.status(500) res.render("error", { error: err }) }
請注意,如果你在你的代碼調用next()出現錯誤多次,則會觸發(fā)默認錯誤處理程序,即使自定義錯誤處理中間件已就緒也是如此。
編寫錯誤處理程序以與其他中間件函數相同的方式定義錯誤處理中間件函數,除了錯誤處理函數有四個參數而不是三個:(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字符串。
對于組織(和更高級別的框架)目的,你可以定義多個錯誤處理中間件函數,就像使用常規(guī)中間件函數一樣,例如,為使用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中的任何剩余處理程序將繼續(xù)執(zhí)行。
對next()和next(err)的調用表明當前處理程序已完成并處于什么狀態(tài),next(err)將跳過鏈中的所有剩余處理程序,除了那些設置為處理上述錯誤的處理程序。上一篇:使用模板引擎 下一篇:調試
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.hztianpu.com/yun/100488.html
摘要:常見問題我該如何構建我的應用程序這個問題沒有明確的答案,答案取決于你的應用程序規(guī)模和所涉及的團隊,為了盡可能靈活,在結構方面沒有做出任何假設。請參閱,了解以模型為中心的基于的框架。 常見問題 我該如何構建我的應用程序? 這個問題沒有明確的答案,答案取決于你的應用程序規(guī)模和所涉及的團隊,為了盡可能靈活,Express在結構方面沒有做出任何假設。 在你喜歡的任何目錄結構中,路由和其他特定于...
摘要:調用堆棧中的下一個中間件函數。此示例顯示了一個中間件子堆棧,它處理對路徑的請求。要從路由器中間件堆棧跳過其余的中間件函數,請調用將控制權傳遞給下一個路由,注意僅適用于使用或函數加載的中間件函數。 使用中間件 Express是一個路由和中間件Web框架,其本身的功能非常?。篍xpress應用程序本質上是一系列中間件函數調用。 中間件函數是可以訪問請求對象(req)、響應對象(res)以及...
摘要:在向頁面發(fā)送內容時,程序也不會往下執(zhí)行我們也可以裝在一組中間件路由級中間件路由級中間件和應用級中間件一樣,只是它綁定的對象為。安裝所需功能的模塊,并在應用中加載,可以在應用級加載,也可以在路由級加載。 Express 框架 根據官方的介紹,Express 是一個基于 Node.js 平臺的極簡、靈活的 web 應用開發(fā)框架,可以輕松的創(chuàng)建各種 web 或者移動端應用 今天就來簡單的了解...
摘要:使用承諾和異步功能來擺脫回調地獄的應用程序,并簡化錯誤處理。它暴露了自己的和對象,而不是的和對象。因此,可被視為的模塊的抽象,其中是的應用程序框架。這使得中間件對于整個堆棧而言不僅僅是最終應用程序代碼,而且更易于書寫,并更不容易出錯。 Koa 與 Express 此系列文章的應用示例已發(fā)布于 GitHub: koa-docs-Zh-CN. 可以 Fork 幫助改進或 Star 關注更新...
摘要:方法此中間件在及更高版本中可用。由于的形狀基于用戶控制的輸入,因此該對象中的所有屬性和值都是不可信的,應該在信任之前進行驗證。注意為獲得最佳結果,請使用反向代理緩存來提高服務靜態(tài)資源的性能。 express() 創(chuàng)建一個Express應用程序,express()函數是express模塊??導出的頂級函數。 var express = require(express); var app ...
閱讀 655·2021-11-18 13:12
閱讀 1394·2021-11-15 11:39
閱讀 2544·2021-09-23 11:22
閱讀 6296·2021-09-22 15:15
閱讀 3729·2021-09-02 09:54
閱讀 2378·2019-08-30 11:10
閱讀 3312·2019-08-29 14:13
閱讀 2967·2019-08-29 12:49