Node.js如何处理健壮性

在极客教育出版了一个视频是关于《Node.js 异常处理-健壮性》,本文章主要是从内容上介绍如何来处理Node.js异常问题。如果希望学习可前往极客学院:http://www.jikexueyuan.com/course/2373.html

本文章的关键词 - 进程退出 - 内存泄漏 - domain安全保护


Node.js 异常的危害

很多初学的同学很少会关注Node.js的服务安全问题,而当服务器在生成环境遇到此类问题时,又会显得速手无策,因此在学习Node.js的初期了解其常见的危害事关重要。Node.js异常带来的危害主要包含两个方面,一个是来自服务器长期的危害,一个则来自服务的致命危害。

服务器致命危害

这里主要说的是由于代码健壮性问题,常常会由于局部的代码问题,导致整个服务功能异常退出,可简单说明为一个用户的异常请求,会影响到整个服务的功能,一个用户会将整个服务失效。最常见的莫过于代码中包含一些异常逻辑,或者一些隐藏的不常调用的触发逻辑导致的生成环境问题。

长期服务危害

由于Node.js是一个常驻内存的server,因此会由于小部分代码泄漏或者小部分句柄未关闭,当服务器请求累积到一定的程度的时候,就会导致服务器的句柄或者内存达到服务器限制,从而必须重启服务才可继续提供用户服务,而在这重启的过程中,往往会导致一些不可预知的问题。

既然有上面的两种比较严重的危害,那么我们应该在哪些场景中注意这些问题呢?

常见的 Node.js 异常逻辑

这里主要是提出一些可能出现异常逻辑的代码,对于初学者可借鉴,如果你是有经验的童鞋请忽略。主要看下面几段代码逻辑。

Node.js的变量异常

var c = a + b;
var a = {'t' : 1}
console.log(a.t);
console.log(a.w);
console.log(a.w.r);

上面一段代码中console.log(a.w.r);这部分代码就会导致服务器的进程异常退出,首先前面两个console.log都是正常的,即使说a.w为null其实也是不会导致代码异常,但是如果使用null.r的话,因为null对象并非包含r属性,因此这部分会抛出Node.js异常,从而会导致整个服务的异常。 对于这点来说我们最好的处理办法就是在使用变量时候最好做一次属性检查,避免出现null.属性的问题,也就是可以优化为如下方式:

var objArr = [{'test':1}, {'test':2}];
objArr[0]['test'];
objArr[2];
if(typeof objArr[2] == 'object'){
    console.log(objArr[2]['test']);
} else {
    console.log('it is not a object');
}

当然对于对象属性检查也是一样的,如下代码会导致异常

var testErrObject = 'dasdasd';
JSON.stringify(testErrObject);

可优化为

var testObject = {'test' : 1};
if(typeof testObject == 'object'){
    console.log(JSON.stringify(testObject));
} else {
    console.log('it is not a object');
}

var testString = '{"key" : "test is a test"}';
if(typeof testString == 'string'){
    console.log(JSON.parse(testString));
} else {
    console.log('it is not a string');
}

以上就是Node.js的变量异常。

Node.js的函数以及调用异常

函数异常主要是在定义时候,以及调用时候。

未申明

在Node.js中如果函数未申明则调用就会很容易出现异常,但是这种错误一般在开发阶段就会发现。对于这种情况我们常见的是在一个module中定义一个未export的函数,而在其他module中调用才会发生。

函数回调异常

这里主要还是针对Node.js中的异步函数,异步函数都是在异步回调中处理返回结果,但是经常会有同学同步的去获取执行结果,导致一直未得到正确的返回,而有些时候这种错误不会被发现,但是当现网运行时会由于某些用户的操作触发该问题。当然下面的代码就是初学者必须要了解的,一般有所经验的Node.js开发者都不会出现。

var fs = require('fs');
var fileData = fs.readFile('./test.txt', function(err, data){

});
console.log(fileData);

上面就是场景的一些异常问题,既然存在问题,那么我们就想想如何去处理这些异常问题。

保证 Node.js 健壮性的方案

这里主要是针对代码异常做的一个健壮性,对于Node.js内存异常的问题,我们会下节课进行讨论分析。 我们来看看三种常见的方案

常见保护逻辑

这里主要是针对一些低级的变量异常、对象调用异常问题,这部分主要的处理就是在调用前进行相应的检测判断,特别是对于对象和数组调用的时候,避免这种异常错误。

var arr = [1, 2, 3];
var obj = {'1' : '1', '2' : '2', '3' : '3'};

console.log(arr[4]);
console.log(obj[4]);

var objArr = [{'test':1}, {'test':2}];
objArr[0]['test'];
objArr[2];
objArr[2]['test'];

前面也介绍了处理方法,上面是调用异常问题,如果我们在调用test属性时,先进行判断再调用就不会出现严重异常问题,如下:

var objArr = [{'test':1}, {'test':2}];
objArr[0]['test'];
objArr[2];
if(typeof objArr[2] == 'object'){
    console.log(objArr[2]['test']);
} else {
    console.log('it is not a object');
}

通用的保护逻辑try catch

try catch的话可以针对所有非异步执行代码的异常问题,只要是在同步调用函数中出现异常,都可以使用try catch来保护,但是对于异步回调函数中如果出现异常时,外层的try catch就无法捕获,因此如果使用try catch保护就会做的很繁琐。 首先我们看一个try catch保护逻辑的示例:

try{
    callErr();
}catch(err){
    console.log(err);
}

function callErr(){
    var s = wrong + true;
    console.log(someSth);
}

上面一段代码中callErr就是一个同步异常代码,这里使用try catch就可以很好的捕获,并且不会导致服务的异常退出。但是如果是如下示例代码时,就会显得有些无力了。

try{
    callErr();
}catch(err){
    console.log(err);
}

function callErr(){
    setTimeout(function(){
        var s = wrong + true;
        console.log(someSth);
    }, 10);
}

如上代码,如果我们还是希望使用try catch来做保护应该怎么做呢?

try{
    callErr();
}catch(err){
    console.log(err);
}

function callErr(){
    setTimeout(function(){
        try{
            var s = wrong + true;
            console.log(someSth);
        }catch(err){
            console.log(err);
        }
    }, 10);
}

虽然上面代码可以解决问题,但是细心的同学可以看到,如果去处理异常会让人奔溃,那么如何才能优雅的处理这种异步回调中的异常捕获呢?

domain的深层次保护

既然大家看到了上面的问题,那么最佳的方案就是使用domain来解决这种异步异常捕获问题。那么如何应用domain来处理呢?请看下面示例代码:

var domain = require('domain');
var d = domain.create();
d.on('error',function(err){
    console.log(err);
});
function callErr(){
    setTimeout(function(){
        var s = wrong + true;
        console.log(someSth);
    }, 10);
}
d.run(function(){
    callErr();
})

非常的简单,就是将需要保护的代码逻辑包裹在d.run的回调函数中即可,这样可以保证整个服务运行期间这部分调用逻辑安全,我最新的myweb2.1就是使用domain来保护整个逻辑的安全。

整体上这部分健壮性的就介绍完了,本次介绍的重点是如何保证服务器的代码逻辑异常,避免代码异常导致的服务器进程退出,关于服务器运行时安全的问题,我们将在下一个视频课时出来以后我这边再做相应的文章编写。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C++

python笔记:#004#注释

1743
来自专栏Golang语言社区

Go语言基于共享变量的并发

一个特定类型的方法和操作函数是并发安全的,那么所有它的访问方法和操作都是并发安全的。导出包级别的函数一般情况下都是并发安全的,package级的变量没法被限制在...

42011
来自专栏Albert陈凯

2018-08-02 IntelliJ IDEA - Debug 调试多线程程序IntelliJ IDEA - Debug 调试多线程程序

https://blog.csdn.net/nextyu/article/details/79039566

2092
来自专栏深度学习自然语言处理

实例快速上手shell脚本

昨天老师给了宗林师兄任务,让我跑一个机器翻译的程序。我看了看就是跑shell脚本。刚开始一看。。我的天。。好长的代码,但是觉得这个时候就更不能怕,得迎难而上,趁...

3769
来自专栏magicsoar

C++编译与链接(2)-浅谈内部链接与外部链接

发现每次写技术博客时,都会在文章开头处花费一番功夫 ...从前,有一个程序员....他的名字叫magicsoar 为什么有时会出现aaa已在bbb中重定义的错误...

2909
来自专栏Phoenix的Android之旅

关于volatile的坑

Java的面试基础问题中,经常出现并发相关的问题。比如volatile关键字,是出现频率相当高的一个问题。 如果说volatile和synchronized的区...

693
来自专栏码生

StackNavigator in react-navigation 传参

使用上面的方法即可进行参数传递 但是我建议当想下一个界面传参数时,使用唯一字段标识

991
来自专栏蓝天

redis的一些简介

Redis是Remote Dictionary Server的缩写,他本质上一个Key/Value数据库,与Memcached类似的NoSQL型数据库。

1101
来自专栏编程

PHP7 下的协程实现

前言 相信大家都听说过『协程』这个概念吧。 但是有些同学对这个概念似懂非懂,不知道怎么实现,怎么用,用在哪,甚至有些人认为yield就是协程! 我始终相信,如果...

3578
来自专栏coding for love

在线商城项目08-数据库创建和商品集合的创建

因为six_tao中没有任何内容。我们需要为其创建一个集合或者插入文档,数据库才会显示。例如:

774

扫码关注云+社区

领取腾讯云代金券