Exception Handling
12003Exception Capture
Thanks to the asynchronous programming model supported by the framework, errors can be captured using try catch. When writing application code, exceptions can be directly captured using try catch everywhere.
// app/service/test.js
try {
const res = await this.ctx.curl('http://eggjs.com/api/echo', {
dataType: 'json'
});
if (res.status !== 200) throw new Error('response status is not 200');
return res.data;
} catch (err) {
this.logger.error(err);
return {};
}According to normal coding practices, all exceptions can be captured and handled in this way, but it is important to be aware of some special coding patterns that may cause issues. To put it informally, our code is all on an asynchronous call chain, with all asynchronous operations connected via await. However, if there is a point that breaks out of the asynchronous call chain, the exception cannot be captured.
// app/controller/home.js
class HomeController extends Controller {
async buy() {
const request = {};
const config = await this.ctx.service.trade.buy(request);
// After placing an order, a verification is needed, and it should not block the current request
setImmediate(() => {
this.ctx.service.trade.check(request).catch(err => this.ctx.logger.error(err));
});
}
}In this scenario, if there is an issue in the service.trade.check code that causes an exception to be thrown during execution, the framework can capture the error uniformly at the outer layer using try catch, but since the code in setImmediate "breaks out" of the asynchronous chain, the error cannot be caught. Therefore, developers need to pay special attention.
Fortunately, the framework provides the ctx.runInBackground(scope) helper method for similar scenarios, which encapsulates another asynchronous chain, and all errors within this scope will be captured.
class HomeController extends Controller {
async buy() {
const request = {};
const config = await this.ctx.service.trade.buy(request);
// After placing an order, a verification is needed, and it should not block the current request
this.ctx.runInBackground(async () => {
// Exceptions here will be captured by Background and logged
await this.ctx.service.trade.check(request);
});
}
}To ensure exceptions are traceable, all thrown exceptions must be of type Error, as only Error types contain stack information, which is helpful for problem localization.
Unified Exception Handling at the Framework Level
The framework provides a unified error handling mechanism through the onerror plugin. This mechanism captures any exceptions thrown in all handling methods (Middleware, Controller, Service) and returns different error content based on the expected response type of the request.
| Request Format Requirement | Environment | errorPageUrl Configuration | Return Content |
|