嘿!你有沒有發現,在撰寫程式的時候,總是會有一些程式碼不斷地重複出現?它們就像是影分身術一樣,在不同的地方出現,做著類似的事情。這些重複的程式碼不僅讓我們的程式變得冗長,也讓修改和維護變得更加困難。
但是,身為一個聰明的開發者,我們怎麼能讓這些重複的程式碼繼續存在呢?就像孫悟空掌握了七十二變一樣,我們也要學會如何把這些重複的程式碼”變”出去,讓我們的程式碼變得更加簡潔和優雅。
除了重複的程式碼,錯誤處理也是我們經常要面對的問題。就像在玩遊戲時遇到 boss 一樣,錯誤總是在關鍵時刻出現,讓我們的程式陷入困境。但是,如果我們提前準備好對策,就可以輕鬆地應對這些錯誤,讓我們的程式穩定運行。
所以,讓我們一起來看看如何通過抽取重複的程式碼和實現全面的錯誤處理,讓我們的程式變得更加強大和可靠吧!相信學會這些技巧,你也能成為一名出色的開發者!
房東不給養鸚鵡 - 那就用 Nuxt + Express + MongoDB 30 天寫一個全端鸚鵡專案。
挑戰人生第一次鐵人賽,就來個佛心分享 side project,從專案發想、規劃、設計、資料庫、開發到部署,技術使用 Nuxt 3、Tailwind CSS、Pinia、Axios、Express、MongoDB,製作一個前後端分離的鸚鵡專案,功能主要介紹食物計算機和聯絡我們,希望可以讓更多人瞭解專案的完整流程 ✨
IT 全文章連結製作可重用的函式
首先,我們在專案的根目錄下新增一個名為 utils
的資料夾,用於存放我們抽取出來的工具函式。
在 utils
資料夾中,我們新增一個名為 handleSuccess.js
的檔案,並添加以下程式碼:
1 | // utils/handleSuccess.js |
這個 handleSuccess
函式用於處理成功回應。它接收四個參數:
res
: Express 的回應物件data
: 要在回應中返回的資料message
: 成功訊息statusCode
: HTTP 狀態碼,預設為 200
函式內部使用res.status()
方法設置 HTTP 狀態碼,然後使用res.json()
方法返回一個包含狀態碼、狀態、訊息和資料的 JSON 物件。
接下來,我們在 utils
資料夾中新增一個名為 appError.js
的檔案,並添加以下程式碼:
1 | // utils/appError.js |
這個 appError
函式用於創建自定義的錯誤物件。它接收三個參數:
httpStatus
:HTTP 狀態碼errMessage
:錯誤訊息next
:Express 的next
函式
函式內部創建一個新的Error
物件,並設置錯誤的屬性,包括錯誤訊息、HTTP 狀態碼和一個表示錯誤是否為操作錯誤的標誌isOperational
。最後,函式返回這個錯誤物件。
這個錯誤物件會被傳遞到 Express 的錯誤處理中間件中,我們稍後會在app.js
中進行處理。
最後,我們在utils
資料夾中新增一個名為handleErrorAsync.js
的檔案,並添加以下程式碼:
1 | // utils/handleErrorAsync.js |
這個 handleErrorAsync
函式是一個高階函式,用於處理異步函式的錯誤。它接收一個異步函式 func
作為參數,並返回一個新的函式。
這個新的函式會執行原始的異步函式 func
,並使用 catch
方法捕獲可能發生的錯誤。如果發生錯誤,就將錯誤傳遞給 Express 的 next
函式,交給錯誤處理中間件進行處理。
使用 handleErrorAsync
函式可以簡化異步函式的錯誤處理,避免了繁瑣的 try...catch
語句。
全面的錯誤處理
有了上面的工具函式,我們就可以在 Express 應用程式中實現更全面的錯誤處理了。
我們回到 app.js
檔案:
添加一個全域的未捕獲異常處理程式:
1 | // 程式出現重大錯誤時 |
這個處理程式會在程式出現未捕獲的異常時觸發。它會記錄錯誤訊息,並在服務處理完所有請求後,停止該 process。
接下來,我們添加一個 404 錯誤處理中間件:
1 | // 404 錯誤 |
這個中間件會在沒有匹配到任何路由時觸發,返回一個 404 錯誤訊息。
然後,我們添加一個開發環境的錯誤處理函式:
1 | const resError = (err, res) => { |
這個函式用於處理開發環境下的錯誤,返回詳細的錯誤訊息,包括錯誤堆疊。
接下來,我們添加一個全域的錯誤處理中間件:
1 | app.use(function (err, req, res, next) { |
這個中間件會捕獲所有的錯誤,並進行處理。如果是資料驗證錯誤,就設置相應的錯誤訊息和 isOperational
標誌,然後呼叫 resError
函式處理錯誤。如果是其他類型的錯誤,就直接呼叫 resError
函式處理。
最後,我們添加一個未捕獲的 Promise 錯誤處理程式:
1 | // 未捕獲到的 catch |
這個處理程式會在有未捕獲的 Promise 錯誤時觸發,記錄錯誤訊息。
在路由中使用工具函式
現在,我們可以在 Express 的路由中使用之前定義的工具函式了。
我們回到 routes/feedback.js
檔案,並在檔案的頂部引入工具函式:
1 | const handleSuccess = require("../utils/handleSuccess"); |
然後,在新增 feedback 的路由中,我們可以使用 handleErrorAsync
函式來處理異步函式的錯誤:
1 | router.post( |
讓我們詳細解釋一下新增的錯誤和成功處理部分:
- 錯誤處理:
- 在進行必填欄位驗證後,如果驗證失敗(即有欄位為空或未定義),我們使用
appError
函式創建一個自定義的錯誤物件。 appError
函式接收兩個參數:HTTP 狀態碼和錯誤訊息。在這裡,我們將狀態碼設為 400(Bad Request),表示客戶端提交的請求有問題。錯誤訊息設為 “姓名、信箱、內容為必填欄位”,明確指出哪些欄位是必填的。- 創建完錯誤物件後,我們使用
return next(appError(...))
,將錯誤物件傳遞給 Express 的next
函式。這會將錯誤交給 Express 的錯誤處理中間件進行處理。 - Express 的錯誤處理中間件會根據錯誤物件的屬性(如狀態碼和訊息)來生成適當的錯誤回應,並將其返回給客戶端。
- 在進行必填欄位驗證後,如果驗證失敗(即有欄位為空或未定義),我們使用
- 成功處理:
- 當新增 feedback 成功時,我們使用
handleSuccess
函式來處理成功回應。 handleSuccess
函式接收四個參數:res
:Express 的回應物件,用於發送回應給客戶端。newFeedback
:新創建的 feedback 資料,作為回應的一部分返回給客戶端。- “新增成功”:成功訊息,告知客戶端新增 feedback 成功。
- 201:HTTP 狀態碼,表示資源已成功創建。
- 在
handleSuccess
函式內部,它會設置適當的 HTTP 狀態碼(如果沒有提供,預設為 200),並將包含狀態、訊息和資料的 JSON 回應返回給客戶端。 - 這樣,客戶端就能收到一個結構化的成功回應,其中包含了新創建的 feedback 資料和成功訊息。
- 當新增 feedback 成功時,我們使用
通過使用 appError
和 handleSuccess
函式,我們將錯誤處理和成功回應的邏輯抽象到了單獨的函式中。這樣做的好處是:
- 程式碼更加簡潔和可讀,不需要在路由處理函式中手動設置 HTTP 狀態碼和回應格式。
- 錯誤處理和成功回應的邏輯被集中管理,提高了程式碼的一致性和可維護性。
- 可以在多個路由處理函式中重複使用這些函式,減少了重複的程式碼。
app.js 完整程式碼
點擊這裡查看完整範例程式碼
1 | var createError = require("http-errors"); |
總結
在本文中,我們學習了如何將重複的程式碼抽取到單獨的函式或模組中,提高程式碼的可讀性和可維護性。我們創建了 handleSuccess
、appError
和 handleErrorAsync
三個工具函式,分別用於處理成功回應、創建自定義錯誤物件和處理異步函式的錯誤。
然後,我們在 Express 應用程式中實現了更全面的錯誤處理,包括全域的未捕獲異常處理、404 錯誤處理、開發環境錯誤處理、全域錯誤處理中間件以及未捕獲的 Promise 錯誤處理。
最後,我們在 Express 的路由中使用了這些工具函式,簡化了路由的錯誤處理邏輯,提高了程式碼的可讀性。
希望通過本文的學習,你能夠更好地理解如何抽取重複的程式碼,並實現更全面的錯誤處理。如果你有任何問題或建議,歡迎在評論區留言討論。
希望這篇文章有幫助到你,謝謝你的觀看,若有想看的系列也歡迎告訴我 😉