Node.js之错误处理

1. 使用 domain 模块处理错误

try..catch

多用于捕捉同步方法中的抛出错误,但不能用try..catch捕捉异步方法中抛出de错误

如:

  1 var http = require('http')
2 try{
3 http.createServer(function(req,res){
4 if(req.url!="/favicon.ico"){
5 noneexist();//不存在本函数
6 res.writeHead(200,{'Content-Type':'text/html'})
7 res.write('<head><meta charset="utf-8"/></head>')
8 res.end('你好\n')
9 }
10 }).listen(8000,"127.0.0.1")
11 }
12 catch(err){
13 console.log('接收客户端请求时发生以下错误:')
14 console.log(err.code)
15 }

在用浏览器请求时,会出错,因为noneexist()不存在,程序也会停止运行

$ node app.js
D:\Users\yuan\Desktop\app.js:6
noneexist();//不存在本函数
^
ReferenceError: noneexist is not defined
at Server.<anonymous> (D:\Users\yuan\Desktop\app.js:6:13)
at emitTwo (events.js:125:13)
at Server.emit (events.js:213:7)
at parserOnIncoming (_http_server.js:602:12)
at HTTPParser.parserOnHeadersComplete (_http_common.js:116:23)

为了防止程序被强制关闭,提供了一个uncaughtException事件,用于捕捉及处理任何未被处理的错误

可将代码改成如下形式:

 var http = require('http')
var http = require('http')
http.createServer(function(req,res){
if(req.url!="/favicon.ico"){
noneexist();//不存在本函数
res.writeHead(200,{'Content-Type':'text/html'})
res.write('<head><meta charset="utf-8"/></head>')
res.end('你好\n')
}
}).listen(8000,"127.0.0.1")
process.on('uncaughtException',function(err){
console.log('接收客户端请求时发生以下错误:')
console.log(err)
})

运行结果如下会报错,但不会停止:

$ node app.js
接收客户端请求时发生以下错误:
ReferenceError: noneexist is not defined
at Server.<anonymous> (D:\Users\yuan\Desktop\app.js:6:13)
at emitTwo (events.js:125:13)
at Server.emit (events.js:213:7)
at parserOnIncoming (_http_server.js:602:12)
at HTTPParser.parserOnHeadersComplete (_http_common.js:116:23)
|

但这种方法可能会出现资源泄露,因此利用domain模块进行处理错误,代码如下:

var http = require('http')
var domain = require('domain')
http.createServer(function(req,res){
var d = domain.create()
d.once('error',function(err){
res.writeHead(200,{'Content-Type':'text/html'})
res.write('<head><meta charset="utf-8"/></head>')
res.write('服务器接收客户端请求时发生以下错误: ')
res.end(err.message)
})
d.run(function(){
if(req.url!=="/favicon.ico"){
nonexist();
res.writeHead(200,{'Content-Type':'text/html'})
res.write('<head><meta charset="utf-8"/></head>')
res.end('你好\n')
}
}) }).listen(8000,"127.0.0.1")

浏览器访问后在浏览器中会出现错误信息,程序不会间断

下面详细介绍Domain

2. 创建并使用Domain

  1. 创建domain对象:

    var domain= domain.create();

  2. 当该对象捕获到任何错误信息时,触发该对象的error事件,可以通过对监听对象的error事件并指定事件回调函数的方法来实现对捕捉到错误时的处理。

     domain.on('error',function(err){
    //事件回调函数代码
    })
  3. 在domain对象中定义了一个name属性值,用于获取Domain对象的名字

    domain。name

  4. Domain对象被创建后,利用run方法指定Domain监视对象

     domain。run(fn)//fn为一函数

eg:

var domain = require('domain')
var fs = require('fs')
var d = domain.create()
d.name = 'dl'
d.on('error',function(err){
console.error(d.name,err)
})
d.run(function(){
process.nextTick(function(){
setTimeout(function(){
fs.open('non-existent file','r',function(err,fd){
if(err)throw err
})
},1000)
})
})

输出结果为:

 $ node app.js
dl { Error: ENOENT: no such file or directory, open 'D:\Users\yuan\Desktop \non-existent file'
errno: -4058,
code: 'ENOENT',
syscall: 'open',
path: 'D:\\Users\\yuan\\Desktop\\non-existent file',
domain:
Domain {
domain: null,
_events: { error: [Function] },
_eventsCount: 1,
_maxListeners: undefined,
members: [],
name: 'dl' },
domainThrown: true }

3. 隐式绑定与显示绑定

当使用Domain对象的run方法指定所有监听的函数时,函数中使用的实例对象都隐式地绑定到Domain对象上。有时需要某些对象不绑定Domain上,或者绑定到另一个Domain上,因此需要显性绑定,利用add方法

domain.add(emitter)

可通过下面例子说明,我们创建一个Http服务器,并指定服务器接收到的客户端请求时,首先创建一个Domain对象,然后使用该对象的add方法分别将用于读取客户端请求数据的http.IncomingMessage对象,与用于发送服务器端响应数据的http.ServerRespanse对象绑定到Domain对象上,并制定当Domain对象那个捕获到错误时客户端返回错误信息。

  1 var http = require('http')
2 var domain = require('domain')
3 http.createServer(function(req,res){
4 var d = domain.create();
5 d.add(req)
6 d.add(res)
7 d.on('error',function(err){
8
9 res.writeHead(200)
10 res.write('服务器接收客户端请求时发生以下错误: ')
11 res.end(err.message)
12
13 })
14
15 res.writeHead(200)
16 req.on('data',function(){
17 bibeexists();
18 res.write('你好')
19 res.end()
20 })
21
22 }).listen(8000)

接下来创建一个用于向Http服务器提供请求的模块文件代码

  1 var http = require('http')
2 var options = {
3 hostname:'localhost',
4 port:8888,
5 path:'/',
6 method:'POST'
7 }
8 var req = http.request(options,function(res){
9 res.setEncoding('utf8')
10 res.on('data',function(chunk){
11 console.log('响应内容:' + chunk)
12 })
13 })
14 req.write('你好')
15 req.end('再见')

分别在不同界面运行以上两个程序,可得,服务器不停止工作,http请求端返回错误数据:

[root@kuber2 webproject]# node client.js
响应内容:服务器接收客户端请求时发生以下错误:
响应内容:noneexists is not defined
[root@kuber2 webproject]#

使用了add方法绑定了Domain,可以使用remove方法解绑,即

domain.remove(emitter)

4 绑定回调函数与拦截回调函数

可以利用bind方法将一个回调函数与Domain绑定在一起

domain.bind(callback)

回调函数中如果有异常将异常抛出给domain,但本方法必须有throw err

eg:

  1 var fs = require('fs')
2 var domain = require('domain')
3 var d = domain.create()
4 fs.readFile('./test.txt',d.bind(function(err,data){
5 if(err) {
6
7 console.log('blind绑定的回调函数抛出的异常:' + err.message)
8 throw err
9 }
10 else console.log(data)
11 })
12 )
13 d.on('error',function(err){
14 console.log('读取文件时发生以下错误:')
15 console.log(err)
16 })

运行所得结果如下:

blind绑定的回调函数抛出的异常:ENOENT: no such file or directory, open './test.txt'
读取文件时发生以下错误:
{ Error: ENOENT: no such file or directory, open './test.txt'
at Error (native)
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: './test.txt',
domain:
Domain {
domain: null,
_events: { error: [Function] },
_eventsCount: 1,
_maxListeners: undefined,
members: [] },
domainThrown: true }
[root@kuber2 webproject]#

使用intercept可以拦截回调函数的异常,使用方法:

domain.intercept(callback)

eg:

  1 var fs = require('fs')
2 var domain = require('domain')
3 var d = domain.create()
4 fs.readFile('./test.txt',d.intercept(function(err,data){
5 console.log(data)
6 })
7 )
8 d.on('error',function(err){
9 console.log('读取文件时发生以下错误:')
10 console.log(err)
11 })

运行结果:

[root@kuber2 webproject]# node app1.js
读取文件时发生以下错误:
{ Error: ENOENT: no such file or directory, open './test.txt'
at Error (native)
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: './test.txt',
domain:
Domain {
domain: null,
_events: { error: [Function] },
_eventsCount: 1,
_maxListeners: undefined,
members: [] },
domainThrown: false,
domainBound: [Function] }
[root@kuber2 webproject]#

5 domain堆栈的弹出与推入

当使用run,bind,intercept方法监听函数时,将把Domain对象推入domai堆栈中,可利用_stack属性查看Domain堆栈内容,堆栈中只能存放一个对象,后这会将前者挤出堆栈。

利用下列代码进行说明:

  1 var domain = require('domain')
2 var d1 = domain.create();
3 d1.name = "d1"
4 var d2 = domain.create();
5 d2.name = 'd2'
6 console.log('原始堆栈:')
7 console.log(domain._stack)
8 d1.run(function(){
9 console.log('d1对象:')
10 console.log(d1)
11 console.log('运行d1对象后的堆栈内容:')
12 console.log(domain._stack)
13 })
14 d2.run(function(){
15 console.log('d2对象:')
16 console.log(d2)
17 console.log('运行d2对象后的堆栈内容:')
18 console.log(domain._stack)
19 })

执行结果如下:

[root@kuber2 webproject]# node app2.js
原始堆栈:
[]
d1对象:
Domain {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
members: [],
name: 'd1' }
运行d1对象后的堆栈内容:
[ Domain {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
members: [],
name: 'd1' } ]
d2对象:
Domain {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
members: [],
name: 'd2' }
运行d2对象后的堆栈内容:
[ Domain {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
members: [],
name: 'd2' } ]
[root@kuber2 webproject]#

可以利用exit方法将Domain对象从domain堆栈中弹出,弹出后不能再捕获错误

eg:

  1 var domain = require('domain')
2 var d = domain.create()
3 d.on('error',function(err){
4 console.log('Domain对象捕获到错误')
5 })
6 console.log('原始堆栈:')
7 console.log(domain._stack)
8 d.run(function(){
9 console.log('运行domain对象后的堆栈内容:')
10 console.log(domain._stack)
11 throw new Error("error")
12 })

此时输出结果为:

[root@kuber2 webproject]# node app3.js
原始堆栈:
[]
运行domain对象后的堆栈内容:
[ Domain {
domain: null,
_events: { error: [Function] },
_eventsCount: 1,
_maxListeners: undefined,
members: [] } ]
Domain对象捕获到错误
[root@kuber2 webproject]#

将domain对象从堆栈中弹出:

  1 var domain = require('domain')
2 var d = domain.create()
3 d.on('error',function(err){
4 console.log('Domain对象捕获到错误')
5 })
6 console.log('原始堆栈:')
7 console.log(domain._stack)
8 d.run(function(){
9 d.exit();
10 console.log('运行domain对象后的堆栈内容:')
11 console.log(domain._stack)
12 // throw new Error("error")
13 })
14

输出结果为:

[root@kuber2 webproject]# node app3.js
原始堆栈:
[]
运行domain对象后的堆栈内容:
[]

domain对象中抛出异常会是程序停止:

  1 var domain = require('domain')
2 var d = domain.create()
3 d.on('error',function(err){
4 console.log('Domain对象捕获到错误')
5 })
6 console.log('原始堆栈:')
7 console.log(domain._stack)
8 d.run(function(){
9 d.exit();
10 console.log('运行domain对象后的堆栈内容:')
11 console.log(domain._stack)
12 throw new Error("error")
13 })
14

输出结果从,程序停止:

/root/webproject/app3.js:12
throw new Error("error")
^
Error: error
at Domain.<anonymous> (/root/webproject/app3.js:12:8)
at Domain.run (domain.js:221:14)
at Object.<anonymous> (/root/webproject/app3.js:8:3)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:389:7)
[root@kuber2 webproject]#

可以使用Domain对象的enter方法将一个Domain对象推入domain堆栈中并使该Domain对象变成当前使用的Domain对象

继续修改上述代码加入enter方法:

  1 var domain = require('domain')
2 var d = domain.create()
3 d.on('error',function(err){
4 console.log('Domain对象捕获到错误')
5 })
6 console.log('原始堆栈:')
7 console.log(domain._stack)
8 d.run(function(){
9 d.exit();
10 console.log('运行domain对象后的堆栈内容:')
11 console.log(domain._stack)
12 d.enter()
13 console.log('运行enter方法后的堆栈内容:')
14 console.log(domain._stack)
15 throw new Error("error")
16 })
17

运行结果:

root@kuber2 webproject]# node app3.js
原始堆栈:
[]
运行domain对象后的堆栈内容:
[]
运行enter方法后的堆栈内容:
[ Domain {
domain: null,
_events: { error: [Function] },
_eventsCount: 1,
_maxListeners: undefined,
members: [] } ]
Domain对象捕获到错误
[root@kuber2 webproject]#

如果多个Domain对象存在嵌套,则会抛出最内层的异常。如果外层用exit方法弹出,则虽有的Domain对象都会被弹出

6. Domain对象的销毁

在一个Domain对象不再使用时,可对其进行销毁

d.dispose()

Node.js之错误处理的更多相关文章

  1. Node.js之错误处理与断言处理

    Node.js之错误处理与断言处理 1. 使用 domain 模块处理错误 try..catch 多用于捕捉同步方法中的抛出错误,但不能用try..catch捕捉异步方法中抛出de错误 如: 1 va ...

  2. Node.js ECONNREFUSED错误

    1 现象 node服务器 遇见此错误,如下:events.js:71throw arguments[1]; // Unhandled 'error' event^Error: connect ECON ...

  3. node.js 标准/错误输出 和 process.exit

    node.js中,各种模块有一种标准的写法: this._process.exec(command, options, function (err, stdout, stderr) { callbac ...

  4. node.js开发错误——DeprecationWarning: Mongoose: mpromise

    原文地址 使用mongoose进行数据库操作时,总是提示: (node:5684) DeprecationWarning: Mongoose: mpromise (mongoose's default ...

  5. node.js常见错误及解决办法

    1.npm express命令行下不能执行 解决办法: 4版本需要安装express-generatorc才能使用express命令npm install -g express-generatorwh ...

  6. 73.node.js开发错误——TypeError: Cannot set property 'XXX' of undefined

    转自:https://blog.csdn.net/fd214333890/article/details/53467429

  7. 61.node.js开发错误——Error: Connection strategy not found

    转自:https://blog.csdn.net/fd214333890/article/details/53457145

  8. Fundebug上线Node.js错误监控啦

    作为全栈JavaScript错误实时监测平台,Fundebug的Node.js实时错误监测服务上线啦,我们能够帮助开发者及时,高效地发现并且解决Node.js错误,从而提高开发效率,并提升用户体验. ...

  9. Node.js log2: ERR when execute command >npm install

    1.Node.js创建项目 项目microblog创建成功,提示:cd  microblog& npm install 项目创建完成时的目录如下图所示: 2.Node.js错误 如题所言: E ...

随机推荐

  1. hdu 1728 逃离迷宫 bfs记步数

    题链:http://acm.hdu.edu.cn/showproblem.php?pid=1728 逃离迷宫 Time Limit: 1000/1000 MS (Java/Others)    Mem ...

  2. TomCatserver的安装,环境的配置,服务的启动以及验证---ShinePans

    首先下载 TomCat 6: http://yunpan.cn/cg5icf3dha4k3  提取码 34c5 然后配置环境变量: 电脑>>>属性>>>高级系统设置 ...

  3. 利用jQuery Ajax技术实现每隔5秒向某页面传值

    有时候我们须要每隔一段时间向某页面传值,比方说聊天室,每隔几秒就像数据库处理页面传值并取回,然后显示在聊天窗体.又或者是每隔一段时间就查询用户最后发言时间到如今是否间隔2分钟.假设是则将用户退出. 这 ...

  4. hdu 1671 Phone List 字典树

    // hdu 1671 Phone List 字典树 // // 题目大意: // // 有一些电话号码的字符串长度最多是10,问是否存在字符串是其它字符串的前缀 // // // 解题思路: // ...

  5. POJ 3683 Priest John&#39;s Busiest Day (2-SAT+输出可行解)

    题目地址:POJ 3683 第一次做须要输出可行解的题目. . .大体思路是先用强连通来推断是否有可行解,然后用逆序建图.用拓扑排序来进行染色.然后输出可行解. 详细思路见传送门 由于推断的时候少写了 ...

  6. PCB Genesis脚本 C#调用Python

    在PCB行业,Genesis的二次开发的编程脚本越来越丰富了啊,从一开始进入眼界的Genesis脚本语言是很少的,CSH,PERL, 再后来慢慢发展,VB,易语言,VB.NET,C#,Java,TCL ...

  7. Salvation -- ---广搜 + 限定方向 ,

    这个欣求 , 在迷宫里密室了方向 , 走过了一个地方 不做标记 还一个劲 , 找不到媳妇不亏 . 这个题 我跳了两个坑 ,  1 : 习惯性添加标记走过的 位置  ,导致所有的位置都能 走过一遍 , ...

  8. BZOJ 4867 分块+神tm卡常

    思路: 注意到len<=10 按照权值max-min<=sqrt(n)*len 分块 记一下前缀和  每修改sqrt(n)次以后重新分块   修改的时候整块打标记  两边重构 (这题常数卡 ...

  9. C++中 list与vector的区别

    引用http://www.cnblogs.com/shijingjing07/p/5587719.html C++ vector和list的区别 1.vector数据结构vector和数组类似,拥有一 ...

  10. iOS - UITableView 单选功能实现

    #import <UIKit/UIKit.h> @interface TestCell : UITableViewCell @property(nonatomic,copy)NSStrin ...