eggjs异常捕获机制
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';
}
}
}
合乎自然而生生不息。。。