1. try catch捕獲異步鏈中的方法
2. ctx.runInBackground(scope)捕獲跳出異步鏈的方法
// 舊代碼
class HomeController extends Controller {
async buy () {
const request = {};
const config = await ctx.service.trade.buy(request);
// 下單后需要進行一次核對,且不阻塞當前請求
setImmediate(() => {
// 這里的異常無法被捕獲到,因為setImmediate跳出異步鏈
ctx.service.trade.check(request).catch(err => ctx.logger.error(err));
});
}
}
// 新代碼
class HomeController extends Controller {
async buy () {
const request = {};
const config = await ctx.service.trade.buy(request);
// 下單后需要進行一次核對,且不阻塞當前請求
ctx.runInBackground(async () => {
// 這里面的異常都會統統被 Backgroud 捕獲掉,並打印錯誤日志
await ctx.service.trade.check(request);
});
}
}
3. 通過中間件攔截上個中間件的異常http code信息攔截
首先eggjs間件機制是一個洋蔥模型。
洋蔥模型解釋如下:
// config.[env].js
exports.middleware = ['gqlErrorHandler','graphql'];
請求先到gqlErrorHandler,再到graphql。
響應先從graphql,再到gqlErrorHandler。
gqlErrorHandler中間件代碼參考如下
const NOTFOUND = 404;
const NORMAL = 200;
module.exports = () => async function notFoundHandler(ctx, next) {
// console.log('中間件經過');
await next();
// console.log('中間件notFoundHandler錯誤攔截', ctx.status, ctx.request.url);
if (ctx.status !== NORMAL && ctx.request.url.indexOf('/gql/') > -1) {
ctx.body = { success: false, message: 'gql解析錯誤', data: null };
ctx.status = NORMAL;
}
if (ctx.status === NOTFOUND) {
ctx.body = { code: NOTFOUND, message: 'Not Found' };
}
};
4. 框架層面的錯誤統一捕獲
如果某個中間件執行異常,會跳過剩下的中間件,直接拋出該異常。
這時需要框架層面的捕獲。
// config.[env].js
exports.onerror = {
all(err, ctx){
// console.log('框架錯誤攔截',err);
if(ctx.request.url.indexOf('/gql/')>-1 && ctx.response.status !== 200){
// console.log('捕獲住了gql錯誤');
ctx.set({
"Content-Type": "application/json"
});
ctx.status = 200;
ctx.body = JSON.stringify({
data:null,
message:'gql解析錯誤',
success: false
});
}
else{
ctx.status = 400;
ctx.body = 'error';
}
}
}
