--- tags: Node.js 直播班 - 2023 春季班 --- # 🏅 Day 22 - 自訂錯誤訊息 我們可以另外新增自定義錯誤訊息的模組,在預期使用者可能會出錯的地方驗證錯誤 **範例**(較完整範例可觀看此 [GitHub](https://github.com/gonsakon/express-week4-sample/blob/week5/service/appError.js)) ```javascript const appError = (httpStatus, errMessage, next)=>{ const error = new Error(errMessage); error.statusCode = httpStatus; error.isOperational = true; next(error); } module.exports = appError; ``` 自訂一個 appError function,將狀態碼及自訂錯誤訊息及 next 參數傳到 function 中 使用 `new Error()` 建立 Error 物件,並設定 Error 回傳的資訊:`statusCode` `isOperational` ,其中 `isOperational` 代表是否為**可預期**的錯誤,因是自訂的錯誤,通常都會設定為 true(可預期) 最後使用 next() 將 Error 交給 app.js 中的錯誤處理 middleware 回傳錯誤訊息 **error handler 範例** ```javascript // error handler // 錯誤處理的 middleware 相較一般 middleware 會多一個 err 引數 app.use(function(err, req, res, next) { err.statusCode = err.statusCode || 500; err.status = err.status || 'error'; res.status(err.statusCode).json({ status: err.status, message: err.message }); }); ``` **使用情境(第六週 JWT)** 假設此路由 /posts 是已登入的會員才能造訪的路由,當接收到的 request 是未通過驗證,則可回傳「未登入」的回饋訊息 ```javascript router.get('/', handleErrorAsync(async(req, res, next) => { // 自訂未通過登入驗證的錯誤 return next(AppError(401, '您並未登入', next)); const timeSort = req.query.timeSort == "asc" ? "createdAt":"-createdAt" const q = req.query.q !== undefined ? {"content": new RegExp(req.query.q)} : {}; const post = await Post.find(q).populate({ path: 'user', select: 'name photo' }).sort(timeSort); res.status(200).json({ status: 'success', results: post.length, data: { post } }); })) ``` ### 參考資源 - [Error - JavaScript | MDN](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Error) - [Express 錯誤處理](https://expressjs.com/zh-tw/guide/error-handling.html) ### 題目(將答案寫在 GitHub 並提交至回報區) 將以下 POST 路由中的註解下方的程式碼改為使用 `appError()` 自訂錯誤資訊,並測試可正確回傳錯誤訊息 routes/posts.js 的 POST 範例 ```javascript router.post('/', async(req, res, next) => { try { const data = req.body; if (!data.content) { // 將以下改為 appError 自訂錯誤回饋 res.status(400).json({ "status": "false", "message": "content 欄位為必填" }); return; } const newPost = await Post.create( { user: data.user, content: data.content, tags: data.tags, type:data.type } ); res.status(200).json({ status: 'success', data: newPost }); } catch (error) { next(error); } }) ``` 可將自己的專案加入 appError.js 自訂錯誤 若沒有也可使用此[專案](https://github.com/dogwantfly/week5-middleware/tree/appError) ## 回報流程 將答案連結貼至底下回報就算完成了喔! 解答位置請參考下圖(需打開程式碼的部分觀看) ![](https://i.imgur.com/vftL5i0.png) <!-- 解答: ```javascript router.post('/', async(req, res, next) => { try { const data = req.body; if (!data.content) { // 錯誤訊息可自行調整 return next(appError(400, "欄位未填寫正確:貼文內容為必填", next)); } const newPost = await Post.create( { user: data.user, content: data.content, tags: data.tags, type: data.type } ); res.status(200).json({ status: 'success', data: newPost }); } catch (error) { next(error); } }) ``` --> 回報區 --- | 報數 | 組別/Discord 名字 | Codepen/HackMD/其他回饋 | |:----:|:-----------------------:|:-------------------------------------------------------------------------:| | 1 | 中 4 組 / jimkk159 | [HackMD - Day 22](https://hackmd.io/M8XYmBJfRomGlkZDUF78hw) | | 1 | 北 10 組 / Benson | [Github - Day 22](https://github.com/ioveasdkre/HexschoolOperation/tree/main/NodejsEnterpriseClass/day40-tasks/day22/app.ts) | | 2 | 北 13 組 / Louisa | [GitHub - Day 22](https://github.com/louisa0416/NodejsEnterpriseClass/blob/master/daily-task/day22/week5-middleware/routes/posts.js) | | 4 | 北 16 組 / 文文 | [GitHub - Day 22](https://github.com/chiawen81/nodeJS_DailyTasks_d20/tree/43cfbad7f4eb18fbbf206cc679a35d2024215187) | | 5 | 南 1 組 / hiYifang | [HackMD - Day 22](https://hackmd.io/@gPeowpvtQX2Om6AmD-s3xw/B1-H4SULc) |