---
tags: Node.js 直播班 - 2022 春季班
---
# 🏅 Day 24
## 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
回報流程
---
請同學依照下圖教學觀看解答、回報答案:

回報格式:請在「回報區」貼上 CodePen 或 HackMD 連結回報答案 (為了統計人數,請同學依序加上「報數」)
<!-- 解答
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)
}
}
```
-->
回報區
---
| 報數 | 組別 / 名字 | codepen / hackMD / 其他回饋 |
| ---- | ------------------ | ------------------------------------------------------- |
| 1 | 第五組 / Hazel | [HackMD@Hazel](https://hackmd.io/@hazelwu/day24) |
| 2 | 第 14 組|East | [HackMD@East](https://hackmd.io/2WD94cSeT8aZdTUHMl0Ffg) |
| 3 | 第 4 組|苡安 | [HackMD](https://hackmd.io/lwe1pMriQNWmK-mY7-nSeA) |
| 4 | 第 3 組 / Jusin | [HackMD](https://hackmd.io/td_KXPwXTLiyBusrxi9CuA) |
| 5 | 第 11 組 / Han Lai | [HackMD](https://hackmd.io/w0Oa8CUtRHS3TCmFR17CRg?view) |
| 6 | 第 4 組 / 小宥 | [HackMD](https://hackmd.io/-yr6g1Z-RW-Q9LLSfcVrBA) |
|7 |第 9 組 / konstante |[HackMD](https://hackmd.io/tEPfwFnDSp6q6EQiCWFS4w?view) |
| 8 | 第 9 組 / 黃士桓 | [HackMD](https://hackmd.io/xnhcTh0PTamHxocPHr5xUg) |
| 9 | 第 3 組 / Hobby | [HackMD](https://hackmd.io/@hobbyling/day24) |
| 10 | 第 12 組 / Jimmy | [HackMD](https://hackmd.io/xQQQe90dT6iULwKqgkyJzQ) |
| 11 | yolala | [HackMD](https://hackmd.io/xQQQe90dT6iULwKqgkyJzQ) |
| 12 | 第 16 組 / 皓皓 | [HackMD](https://hackmd.io/@cutecat8110/BJqgFxfuq) |
| 13 | 第 2 組 / wendy | [HackMD](https://hackmd.io/80FIwll1QUa4u0-WoBv-hQ#20220511)|