zoukankan      html  css  js  c++  java
  • Node.js之错误处理

    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('你好
    ')
      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:UsersyuanDesktopapp.js:6
    noneexist();//不存在本函数
    ^
    ReferenceError: noneexist is not defined
    at Server.<anonymous> (D:UsersyuanDesktopapp.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('你好
    ')
          }
     }).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:UsersyuanDesktopapp.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('你好
    ')
    	}
         })
          
     }).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:UsersyuanDesktop 
    on-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()
  • 相关阅读:
    [Qt] 文本文件读写, 摘自官方文档
    [Windows] Socket Server Failed to bind, error 10048
    lodctr /R 失败的情况
    ModuleNotFoundError: No module named 'sklearn.cross_validation'
    [Qt] 通过socket将另一个程序的某个窗口调到最前端
    SortedDictionary<TKey, TValue> 类 表示根据键进行排序的键/值对的集合。
    finally不管有没有错都会运行 finally 块用于清除 try 块中分配的任何资源,以及运行任何即使在发生异常时也必须执行的代码
    HttpWebRequest使用证书请求
    string StartsWith 方法 Https
    设置https验证方式
  • 原文地址:https://www.cnblogs.com/yuanchenghao/p/7428327.html
Copyright © 2011-2022 走看看