koa錯(cuò)誤處理
使用koa的時(shí)候富玷,對(duì)錯(cuò)誤的處理是比較方便直接的,我們可以寫一個(gè)以下的中間件來處理錯(cuò)誤:
module.exports?=?function?()?{
??return?async?(ctx,?next)?=>?{
????try?{
??????await?next()
??????//?通過ctx來判斷程序執(zhí)行狀態(tài)嗡贺,進(jìn)行一些額外的處理
????}?catch?(err)?{
??????//?處理throw錯(cuò)誤
????}
??}
}
這個(gè)中間件需要在路由之前引入。這樣next就是去處理路由的業(yè)務(wù)邏輯鞍帝,并且由于try catch的存在诫睬, throw出來的error都可以被捕獲到并返回給接口調(diào)用方。這樣可以有一個(gè)強(qiáng)一致的接口返回?cái)?shù)據(jù)結(jié)構(gòu)帕涌,避免造成前端代碼錯(cuò)誤摄凡。
同時(shí)续徽,可以在接口里自定義錯(cuò)誤格式,比如接口參數(shù)錯(cuò)誤亲澡,登錄密碼錯(cuò)誤等钦扭,在接口代碼里throw出來,然后在這個(gè)中間件里進(jìn)行統(tǒng)一識(shí)別處理床绪,這樣土全,可以做到錯(cuò)誤的統(tǒng)一處理,代碼可以寫的比較簡(jiǎn)潔会涎。
express錯(cuò)誤處理
用過express的人都知道裹匙,express的錯(cuò)誤是通過next(err)來傳導(dǎo)的,這樣末秃,throw的錯(cuò)誤假如沒有通過代碼去捕獲的話概页,很容易造成整個(gè)express app都崩潰。很多人寫代碼都是在每個(gè)中間件里進(jìn)行try catch, 然后把catch到的err通過next(err)通知express進(jìn)行錯(cuò)誤處理练慕。這樣會(huì)有很多重復(fù)的代碼惰匙,而且無(wú)法做到接口代碼無(wú)感知處理接口錯(cuò)誤。
我們可以寫一個(gè)適配器處理這個(gè)問題:
module.exports?=?class?AppRouteAdapter?{
??constructor?(realApp)?{
// realApp是express實(shí)例
????this.realApp?=?realApp
// 這里支持get, put,post,patch, delete方法铃将,假如需要支持新的方法项鬼,可以加在這個(gè)數(shù)組里面
????let?methods?=?['get',?'put',?'post',?'patch',?'delete']
????methods.forEach((action)?=>?{
// 動(dòng)態(tài)添加http請(qǐng)求方法
??????this[action]?=?this.method.bind(this,?action)
????})
??}
??_isAsyncFunc?(func)?{
????//?console.log(this.curApi,?func)
????const?string?=?func.toString().trim()
????return?string.indexOf('async')?===?0
??}
??_toAsyncMiddleware?(middleware)?{
????let?realApp?=?this.realApp
????return?this._isAsyncFunc(middleware)???middleware?:?async?function?()?{?middleware.apply(realApp,?Array.prototype.slice.call(arguments,?0))?}
??}
??//?把路由中間件合并成一個(gè),支持中間件嵌套執(zhí)行劲阎。
??_combineMiddleware?(middlewares?=?[])?{
????let?realApp?=?this.realApp
????return?async?function?(req,?res,?next)?{
??????let?nextMiddleware?=?next
??????for?(let?i?=?middlewares.length?-?1;?i?>=?0;?i--)?{
????????nextMiddleware?=?middlewares[i].bind(realApp,?req,?res,?nextMiddleware)
??????}
??????return?nextMiddleware()
????}
??}
??route?(api)?{
????this.curApi?=?api
????return?this
??}
??method?(action,?...middlewares)?{
????let?newMiddlewares?=?middlewares.map((middleware)?=>?{
??????let?asyncMiddleware?=?this._toAsyncMiddleware(middleware)
??????return?async?(req,?res,?next)?=>?{
????????return?asyncMiddleware(req,?res,?next).catch(next)
??????}
????})
????//?假如要支持中間件嵌套绘盟,可以使用this._combineMiddleware來合并成一個(gè)中間件
????//?this.realApp.route(this.curApi)[action](this._combineMiddleware(newMiddlewares))
????this.realApp.route(this.curApi)[action](newMiddlewares)
??}
}
假設(shè)我們的路由注冊(cè)方式是這樣的:
app.route('/api/example').get((req, res, next) => next(), (req, res, next) => res.send('response'))
其中, app是express實(shí)例悯仙, 注冊(cè)了/api/example的路由龄毡,使用get方法,有兩個(gè)中間件锡垄。
我們使用:
let?adapter?=?new?AppRouteAdapter(app)
adapter.route('/api/example').get((req, res, next) => next(), (req, res, next) => res.send('response'))
把a(bǔ)pp換成adapter, 來進(jìn)行路由注冊(cè)沦零。
那么這個(gè)adapter做了什么呢?
1. 把2個(gè)中間件都轉(zhuǎn)換成async function,
2.?所有async的中間件使用.catch(next)進(jìn)行統(tǒng)一錯(cuò)誤捕獲货岭,并把錯(cuò)誤傳給next路操,讓express的錯(cuò)誤處理中間件可以進(jìn)行處理。
這樣千贯,也就實(shí)現(xiàn)了前面koa說擁有的那些錯(cuò)誤處理的優(yōu)點(diǎn)屯仗。