本系列目录
1. 全局 点我去看
2. 路由匹配 点我去看
3. 错误处理 (本文)
4. 视图模板 点我去看
5. 设计思想 点我去看
1. 常用语言的错误捕获
1.1 C:约定发生错误时的返回值,比如 api函数返回NULL,-1,'\0' 等
FILE *fp;
if( (fp=fopen("D:\\demo.txt","rb") == NULL ){
printf("Fail to open file!\n");
exit(0); //退出程序(结束程序)
}
1.2 c++:try...catch...catch... throw
try {
语句组
}
catch(异常类型) {
异常处理代码
}
...
catch(异常类型) {
异常处理代码
}
1.3 java: try...catch...catch...finally throw
try{
}catch(异常类型) {
异常处理代码
}
...
catch(异常类型) {
异常处理代码
}
finally{
}
1.4. Go语言:放在返回值的特定位
func test(n float64) (float64, error) {
if n < 0 {
return 0, errors.New("error")
}
// 实现
}
result, err:= test(-1)
if err != nil {
fmt.Println(err)
}
为什么我要看别的语言是怎么进行错误捕获的呢?一方面是尝试在别的语言上找到错误捕获的经验,更重要的是,javaScript本来就是解释型语言,底层是V8也就是c/c++,了解他们的错误捕获对研究javaScript本身的错误出现的原因,怎么去捕获是非常有必要的,即使在语法层面可以用try...catch。
2. 哪些地方可能报错?
当js出错的时候,一个error对象就会被建立,本来这小节是想在v8源码里找找到底js的错误是怎么从c++底层通知到js语言层的,奈何国内在v8源码这方面的资料实在是很难找,自己这蹩脚英语看国外文章有慢的一批,找来源码看看,看了几小时,看不出个所以然来,就此放下,等日后有时间再回过头来,攻克v8,于是只能说说js层面可能出错的地方
在js语言层面上可能出现错误的地方还是挺统一的,主要在以下几个方面
JS
语法错误、代码异常- 编译阶段出错
- 执行阶段出错
AJAX
请求异常- 静态资源加载异常
Promise
异常Iframe
异常- 跨域 Script error
- 崩溃和卡顿
对于一个服务器框架来说,对错误的处理可以说是至关重要,回到主题,看看Express内部的错误是怎么处理的
3. Express的错误处理
首先我们要清楚,对于一个框架来说,错误更多的并不是语言本身出错,或者一些意想不到的地方报错,而是用户,也就是开发人员不合法使用框架,框架本身报的自定义错误,这种错误使用一般会对框架本身产生毁灭性的影响,所以不得不抛出一个错误告诉开发人员。
Express内部的错误有以下几种
3.1 自定义错误,尝试引用不存在的属性、方法、对象
- 一些废弃的中间件
var removedMiddlewares = [
'bodyParser',
'compress',
'cookieSession',
'session',
'logger',
'cookieParser',
'favicon',
'responseTime',
'errorHandler',
'timeout',
'methodOverride',
'vhost',
'csrf',
'directory',
'limit',
'multipart',
'staticCache'
]
removedMiddlewares.forEach(function (name) {
Object.defineProperty(exports, name, {
get: function () {
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
},
configurable: true
});
});
- 对象上废弃的属性
Object.defineProperty(this, 'router', {
get: function () {
throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.');
}
});
这错报的无可厚非,都不存在了,肯定引用失败
3.2 自定义错误,不合语法的使用
- router.use没有传入中间件函数
var callbacks = flatten(slice.call(arguments, offset));
if (callbacks.length === 0) {
throw new TypeError('Router.use() requires a middleware function')
}
//...
if (typeof fn !== 'function') {
throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
}
- route.all没有传入callback
if (typeof handle !== 'function') {
var type = toString.call(handle);
var msg = 'Route.all() requires a callback function but got a ' + type
throw new TypeError(msg);
}
3.3 使用拓展包时可能报的错
- decodeURIComponent
try {
return decodeURIComponent(val);
} catch (err) {
if (err instanceof URIError) {
err.message = 'Failed to decode param \'' + val + '\'';
err.status = err.statusCode = 400;
}
throw err;
}
还遵循只catch明确知道的错误原则,代码质量杠杠的
- parseUrl
// get pathname of request
function getPathname(req) {
try {
return parseUrl(req).pathname;
} catch (err) {
return undefined;
}
}
3.4 中间件执行过程中的报错
中间件执行过程是Express最复杂的过程,报错的原因有很多,比如说中间件函数执行出错,匹配layer出错等,在内部,统一用一个layerError变量表示这种错误,每次执行下一个中间件之前都要检查有没有错误,有的话终止执行,并将错误向下传递,直到被专门的错误处理函数处理,就像是promise链一样
流程的错误捕获
function next(err) {
var layerError = err === 'route' ?
null :
err;
// remove added slash
if (slashAdded) {
req.url = req.url.substr(1);
slashAdded = false;
}
// restore altered req.url
if (removed.length !== 0) {
req.baseUrl = parentUrl;
req.url = protohost + removed + req.url.substr(protohost.length);
removed = '';
}
// signal to exit router
if (layerError === 'router') {
setImmediate(done, null)
return
}
//codes ....
}
专门处理错误的layer
Layer.prototype.handle_error = function handle_error(error, req, res, next) {
var fn = this.handle;
if (fn.length !== 4) {
// not a standard error handler
return next(error);
}
try {
fn(error, req, res, next);
} catch (err) {
next(err);
}
};
4. 总结
Express的错误捕获分为框架相关错误和框架无关错误,框架相关错误会使框架直接崩溃,比如说用不合语法,框架无关错误一般是中间件流执行的时候发生的意料之外的错误,交由专门的error-handle layer处理,比如如下
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
参考