--- tags: Node.js 直播班 - 2023 春季班 --- # 🏅 Day 23 - development 及 production 環境變數指令、客製錯誤訊息 由於通常不會將開發時遇到的詳細錯誤資訊(如 error.stack)呈現在客戶端,避免過多資訊暴露而有資安疑慮,因此會區分 development 及 production 模式下的錯誤訊息 可在錯誤處理 (error handler) middleware 判斷 Node.js 環境變數 `process.env.NODE_ENV` 為 `dev` 或是 `production`(下方 error handler 範例 31 及 33 行),以提供不同錯誤處理 :::spoiler error handler 範例(點擊展開) ```javascript= // 自己設定的 err 錯誤 const resErrorProd = (err, res) => { if (err.isOperational) { res.status(err.statusCode).json({ status: err.status, message: err.message }); } else { // log 紀錄 console.error('出現重大錯誤', err); // 送出罐頭預設訊息 res.status(500).json({ status: 'error', message: '系統錯誤,請恰系統管理員' }); } }; // 開發環境錯誤 const resErrorDev = (err, res) => { res.status(err.statusCode).json({ status: err.status, message: err.message, error: err, stack: err.stack }); }; // error handler app.use(function(err, req, res, next) { err.statusCode = err.statusCode || 500; err.status = err.status || 'error'; if (process.env.NODE_ENV === 'dev') { resErrorDev(err, res); } else if (process.env.NODE_ENV === 'production') { if(err.isAxiosError == true){ err.message = "axios 連線錯誤"; err.isOperational = true; return resErrorProd(err, res) } else if (err.name === 'ValidationError'){ // mongoose 資料辨識錯誤 err.isOperational = true; return resErrorProd(err, res) } resErrorProd(err, res) } }); ``` ::: 範例中分別以 `resErrorDev(err, res)` `resErrorProd(err, res)` 回傳不同模式回饋錯誤的 JSON 資料 Production 模式會依據是否為預期 client 端可能會出現的錯誤,決定是否回傳提示 client 端錯誤處,若為 server 端需處理的錯誤,則回傳「系統錯誤,請恰系統管理員」的文字,不需回傳相關錯誤資訊 -- 設定好不同模式的錯誤回饋後,在 package.json 設定設定執行指令,測試不同模式是否有正確回饋錯誤訊息 ```json "scripts": { "start:dev": "NODE_ENV=dev nodemon ./bin/www", "start:production": "NODE_ENV=production nodemon ./bin/www" }, ``` 若是 windows 系統可能會遇到不支援執行以上指令的情況,可安裝 [cross-env 套件](https://www.npmjs.com/package/cross-env) 並調整為以下指令 ```json "scripts": { "start:dev": "cross-env NODE_ENV=dev nodemon ./bin/www", "start:production": "cross-env NODE_ENV=production nodemon ./bin/www" }, ``` <!-- ### 參考資源 --> [GitHub 範例](https://github.com/gonsakon/express-week4-sample/blob/week5/app.js#L47-L86) ### 題目(將答案寫在 GitHub 並提交至回報區) 參考上方 error handler 範例,設計 POST 新增貼文時的 development 及 production 模式的錯誤處理,並以 POSTMAN 測試可正確運作 情境: - request body 的 JSON 資料格式錯誤(缺少 `}`) ```json // production 模式 { "status": 400, "message": "資料格式錯誤" } // devlopment 模式 { "status": 400, "message": "Unexpected end of JSON input", "error": { "expose": true, "statusCode": 400, "status": 400, "body": "{\n \"name\": \"test1\",\n \"content\": \"test1\",\n \"tags\": [\"感情\"],\n \"type\": \"person\"\n", "type": "entity.parse.failed" }, "stack": "SyntaxError: Unexpected end of JSON input\n at JSON.parse (<anonymous>)\n ...略" } ``` 也可以其他錯誤情境練習,有正確回饋 development 及 production 模式的錯誤就 ok ## 回報流程 將答案連結貼至底下回報就算完成了喔! 解答位置請參考下圖(需打開程式碼的部分觀看) ![](https://i.imgur.com/vftL5i0.png) <!-- 解答: error handler 範例參考(也可自行依需求設計) ```javascript const errorHandler = (err, req, res, next) => { err.statusCode = err.statusCode || 500; err.status = err.status || 'error'; if (process.env.NODE_ENV === 'dev') { resErrorDev(err, res); } else if (process.env.NODE_ENV === 'prod') { if (err.isAxiosError == true){ err.message = "axios 連線錯誤"; err.isOperational = true; return resErrorProd(err, res) } else if (err.name === 'ValidationError'){ // mongoose 資料辨識錯誤 err.isOperational = true; return resErrorProd(err, res) } else if (err.name === 'SyntaxError') { err.statusCode = 400 err.isOperational = true; err.message = '資料格式錯誤'; } resErrorProd(err, res) } } ``` --> 回報區 --- | 報數 | 組別/Discord 名字 | Codepen/HackMD/其他回饋 | |:----:|:-----------------------:|:-------------------------------------------------------------------------:| | 1 | 中 4 組 / jimkk159 | [HackMD - Day 23](https://hackmd.io/FUKUO4afTKqWpUZfrI3X5Q) | | 1 | 北 10 組 / Benson | [Github - Day 23](https://github.com/ioveasdkre/HexschoolOperation/tree/main/NodejsEnterpriseClass/day40-tasks/day23/app.ts) | | 2 | 北 13 組 / Louisa | [GitHub - Day 23](https://github.com/louisa0416/NodejsEnterpriseClass/blob/master/daily-task/day23/week5-middleware/service/errorHandler.js) | | 4 | 北 16 組 / 文文 | [GitHub - Day 23](https://github.com/chiawen81/nodeJS_DailyTasks_d20/tree/60c8439a66efdae42901d6601e86f87fbe23ff1c) |