# 🏅 Day 22 - 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=
// production 環境錯誤
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: '系統錯誤,請恰系統管理員'
});
}
};
// 開發環境錯誤(development)
const resErrorDev = (err, res) => {
res.status(err.statusCode).json({
message: err.message,
error: err,
stack: err.stack
});
};
// error handler
app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
if (process.env.NODE_ENV === 'dev') {
return resErrorDev(err, res);
} else if (process.env.NODE_ENV === 'production') {
if (err.name === 'ValidationError'){
// mongoose 資料辨識錯誤
err.message = "資料欄位未填寫正確";
err.isOperational = true;
return resErrorProd(err, res)
}
resErrorProd(err, res)
}
});
```
:::
> 範例中分別以 `resErrorDev(err, res)` `resErrorProd(err, res)` 回傳不同模式回饋錯誤的 JSON 資料
> Production 模式會依據是否為預期 client 端可能會出現的錯誤,決定是否回傳提示 client 端錯誤處裡(使用 `err.name` 錯誤的名稱來判斷設定不同錯誤時回傳不同的錯誤訊息)。若為 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"
> },
> ```
<br>
可參考:[GitHub 範例](https://github.com/gonsakon/express-week4-sample/blob/week5/app.js#L47-L86)
題目
---
延續上方 error handler 範例,設計新增貼文時資料格式錯誤(SyntaxError)的 development 及 production 模式的錯誤處理。
當 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 ...略"
}
```
調整下方程式碼 `...` 的部分
```javascript=
app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
if (process.env.NODE_ENV === 'dev') {
return resErrorDev(err, res);
} else if (process.env.NODE_ENV === 'production') {
if (err.name === 'ValidationError'){
// mongoose 資料辨識錯誤
err.message = "資料欄位未填寫正確";
err.isOperational = true;
return resErrorProd(err, res)
} else if (err.name === 'SyntaxError') {
...
}
resErrorProd(err, res)
}
});
```
## 回報流程
將答案寫在 CodePen 並複製 CodePen 連結貼至底下回報就算完成了喔!
解答位置請參考下圖(需打開程式碼的部分觀看)
![](https://i.imgur.com/vftL5i0.png)
<!-- 解答:
app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
if (process.env.NODE_ENV === 'dev') {
return resErrorDev(err, res);
} else if (process.env.NODE_ENV === 'production') {
if (err.name === 'ValidationError'){
// mongoose 資料辨識錯誤
err.message = "資料欄位未填寫正確";
err.isOperational = true;
return resErrorProd(err, res)
} else if (err.name === 'SyntaxError') {
err.isOperational = true;
err.message = '資料格式錯誤';
return resErrorProd(err, res)
}
resErrorProd(err, res)
}
});
-->
回報區
---
<!--
將答案貼至下方表格內,格式:
| Discord 暱稱 | [CodePen](連結) |
-->
| Discord | CodePen / 答案 |
|:-------------:|:-----------------:|
| xxx | [CodePen]() |
| 苡安 | [hackmd](https://hackmd.io/@L7K9-66lSeagS28AP0_GjQ/Sy2Jj2WGA) |
|Lobinda|[HackMD](https://hackmd.io/@Lobinda/B1laDhWzA)|
| 2魚 | [CodePen](https://codepen.io/ijrekmsn-the-sans/pen/GRLbmvZ) |
| Aida | [CodePen](https://codepen.io/ada23410/pen/mdgZmwV?editors=0010) |
| jenny7532 | [CodePen](https://codepen.io/wei-chen-wu/pen/XWQLRww) |
| Chia Pin | [CodePen](https://codepen.io/joker-cat/pen/YzMorJw) |
| wei | [CodePen](https://hackmd.io/@xu7yoa5cSsqaron7h9XhUw/SkVoXNfG0) |
| ej_chuang | [CodePen](https://codepen.io/EJChuang/pen/WNWqVyv) |
| william威良 | [CodePen](https://codepen.io/snowman12320/pen/VwNovOM?editors=1010) |
| runweiting | [CodePen](https://codepen.io/weiting14/pen/JjVgWOO) |
| Tiya | [CodePen](https://codepen.io/Tiya_blank/pen/rNbQPbY) |
| tung030374 | [CodePen](https://codepen.io/tung__u/pen/OJGKrRB) |
| william_hsu | [CodePen](https://codepen.io/william8815/pen/dyEbqJV) |
| Hank | [CodePen](https://codepen.io/tw1720/pen/eYaYNNB) |
|Mei| [Codepen](https://codepen.io/l_umei/pen/BaeywNG)|