作開發的基本都知道異常
,像Android
開發中常見的ANR
異常、空指針
異常,服務器開發中常常遇到的異常404,500
異常,還有一些其餘常見的異常,具體可見HTTP狀態碼。數據庫
基本上這些異常能夠總結爲:已知異常
和未知異常
。api
已知異常就是程序中可以預想到異常,好比:服務器接口開發中某個api
接口須要5
個參數,而用戶傳遞的參數多餘5個
或者少於5個
,這種錯誤就是已知錯誤。服務器
未知異常就說程序中不能預想到的異常,好比:服務器接口開發中遇到了空指針而程序中又沒有作相應處理就會拋出HTTP
狀態碼爲500
的這種異常,這種就說未知異常。微信
當遇到異常時若是沒有全局異常處理,通常是在相應的代碼邏輯中添加異常捕捉(try ... catch)
或者拋出(throw)
處理。網絡
這麼作實際上是有弊端的:app
類、文件
下寫異常判斷邏輯。以上只是列舉的幾個弊端,爲了解決以上的問題程序中添加全局異常的處理就頗有必要了。async
這裏使用的是NodeJS+Koa2
開發。在Koa
中,中間件是無處不在,因此這裏全局異常的處理也是經過中間件的方式去實現。工具
一、明確是否須要拋出異常開發工具
在服務器接口開發中須要明確是生產環境
仍是開發環境
。ui
在生產環境
中若是出現異常須要將詳細的異常信息上報同時將異常狀態經過api
返回給客戶端處理
在開發環境
中若是出現異常則須要將詳細的異常信息在開發工具的控制檯顯示,同時返回將異常狀態經過api
返回給客戶端處理。
這裏的區別就說生產環境
和開發環境
,因此經過定義一個全局變量去判斷便可。因爲程序中全局變量可能不止一個,爲了統一聲明全局變量,咱們將全部的全局變量放在一個文件中,統一去加載。
新建一個config.js
,裏面的environment:'dev'
就是對環境聲明的變量,這裏dev
表示開發環境
,prod
表示生產環境
。
module.exports = { // prod 表示生產環境 environment:'dev', database:{ dbName:'book', host:'localhost', port:3306, user:'用戶名', password:'密碼', }, // token 設置爲1天 security:{ secretKey:"密鑰,要記住不能弄丟了哦", expiresIn:60*60*24 }, host:'http://localhost:3000/' }
配置了全局變量以後,在init.js
文件的InitManager
類中定義靜態方法:
/** * 加載全局配置文件 * @param {''} path 當前路徑 */ static loadConfig(path = '') { const configPath = path || process.cwd() + '/config/config.js' const config = require(configPath) global.config = config } /** * 加載全局異常 */ static loadHttpException(){ const errors = require('./http-exception') global.errs = errors }
最後在app.js
中完成初始化。
const app = new Koa() InitManager.loadConfig() InitManager.loadHttpException()
定義全局變量以後就須要制定返回的api
異常描述
二、定義異常的返回結果
在服務器接口開發中,一個異常的返回結果,一般包含有:
msg
:異常描述errorcode
:自定義的異常狀態碼code
:網絡請求的狀態碼兩個code
的區別:
errorcode
:自定義的錯誤碼,配合code
定位具體的異常。code
:網絡請求的狀態碼,如403 權限受限
,而權限受限的緣由有不少種,好比未登陸或者登陸了可是權限不足,這時候能夠結合自定義的錯誤碼和異常描述準確明確告知用戶出錯的緣由。定義異常描述以後就須要去判斷程序是已知異常仍是未知異常。
三、明確是已知異常仍是未知異常
已知異常:能夠定義HttpException
繼承Error
這個類,只要是出現這異常屬於HttpException
都屬於已知異常。
http-exception.js
/** * 默認的異常 */ class HttpException extends Error{ constructor(msg='服務器異常',errorCode=10000, code=400){ super() this.errorCode = errorCode this.code = code this.msg = msg } } /** * 資源未找到提示 */ class NotFound extends HttpException{ constructor(msg, errorCode) { super() this.msg = msg || '資源未找到' this.errorCode = errorCode || 10000 this.code = 404 } } module.exports = { HttpException, NotFound }
環境變量聲明瞭、異常也作了處理,那麼如何監聽全局異常呢?
四、全局異常監聽
首先編寫捕捉異常處理中間件catchError.js
const {HttpException} = require('../core/http-exception') const catchError = async (ctx, next)=>{ try { await next() } catch (error) { // 已知異常 const isHttpException = error instanceof HttpException // 開發環境 const isDev = global.config.environment === 'dev' // 在控制檯顯示未知異常信息:開發環境 不是HttpException 拋出異常 if(isDev && !isHttpException){ throw error } /** * 是已知錯誤,仍是未知錯誤 * 返回: * msg 錯誤信息 * error_code 錯誤碼 * request 請求的接口路徑 */ if(isHttpException){ ctx.body = { msg:error.msg, error_code:error.errorCode, request:`${ctx.method} ${ctx.path}` } ctx.status = error.code } else{ ctx.body = { msg: '服務器出現了未知異常', error_code: 999, request:`${ctx.method} ${ctx.path}` } ctx.status = 500 } } } module.exports = catchError
而後在app.js
中加載中間件
const catchError = require('./middlewares/exception') const app = new Koa() // 全局異常中間件監聽、處理,放在全部中間件的最前面 app.use(catchError) app.listen(3000)
以上就完成了全局異常的處理,接下來就是如何使用這個全局異常了。
五、出現異常後及時拋出異常
這裏以資源未找到
爲例。在查詢數據庫中,有的時候會出現數據找不到狀況,這是用就能夠拋出資源未找到
的異常。
在models/book.js
/** * 獲取書籍詳情 * @param {書籍id} bid */ static async detail(bkid) { const book =await Book.findOne({ where: { bkid } }) if (!book) { // 經過全局異常的方式,拋出資源未找到的錯誤 throw new global.errs.NotFound() } return book }
諮詢請加微信:輕撩便可。