2012-11-05 37 views
14

Tôi muốn sử dụng Miền Node.js để bắt ngoại lệ. Nó đang làm việc cho đến nay, nhưng có một nơi tôi không thể có được các lĩnh vực để bắt ngoại lệ. exception2 trong callback bị bắt và xử lý trong domain.on ('error') handler, nhưng exception1 không bị bắt. Điều kỳ lạ là khi exception1 được ném, nó không tắt nút như tôi mong đợi. Dưới đây là ví dụ của tôi ứng dụng:Không thể xử lý ngoại lệ với miền node.js bằng cách sử dụng express

var domain = require('domain'); 
var request = require('request'); 
var express = require('express'); 

var serverDomain = domain.create(); 
serverDomain.on('error', function(err) { 
    console.log("Server Domain Error: " + err); 
}); 

var app; 

serverDomain.run(function() { 
    app = express(); 
    app.listen(3000); 
}); 

app.use(function(req, res, next) { 

    var reqDomain = domain.create(); 
    reqDomain.add(req); 
    reqDomain.add(res); 
    reqDomain.on('error', function(err) { 
    console.log("Req Domain Error: " + err); 
    reqDomain.dispose(); 
    next(err); 
    }); 

    next(); 
}); 

app.get('/', function(req, res) { 
    var uri = "http://google.com"; 

    exception1.go(); 

    request.get({url:uri, json: {}}, 
    function (error, response, body) { 
     if(response.statusCode === 200) { 
     exception2.go(); 
     res.send('Success getting google response'); 
     } 
    }); 
}); 

Để có được exception2 để thực hiện, tôi nhận xét ra ngoại lệ 1.

Trả lời

18

Vấn đề là các ngoại lệ xảy ra trong Connect's routing, trong đó có cả một khối try/catcharound its execution, cũng như trình xử lý lỗi mặc định sẽ in ra chi tiết dấu vết ngăn xếp khi chạy trong chế độ phi sản xuất. Kể từ khi ngoại lệ được xử lý bên trong Express, nó không bao giờ đạt đến lớp bên ngoài của bạn cho các tên miền để xử lý.

Cách khác với exception2 là chức năng xử lý cho tuyến đường '/' được thực hiện trực tiếp bởi khối Kết nối đó, trong cùng một ngăn như cuộc gọi ban đầu đi qua Express. Ngoại lệ thứ hai xảy ra trong một cuộc gọi lại , sau khi một số hoạt động I/O đã quay trở lại và do đó được thực hiện bởi một ngăn xếp bắt nguồn từ bộ điều khiển vòng lặp I/O của sự kiện Node, và do đó không thể có được try/catch Express và lưu máy chủ ứng dụng. Trong thực tế, nếu bạn nhận xét tất cả các công cụ miền, và chuyến đi exception2 nó sẽ làm hỏng Nút.

Vì chỉ có các ngoại lệ không được xử lý được chuyển đến cơ chế miền và vì exception1 có thể hiển thị try/catch trong ngăn xếp cuộc gọi ở trên nó, ngoại lệ được xử lý và không được chuyển tiếp đến miền.

+0

Vì vậy, ngoại lệ sẽ bị bắt bởi trình xử lý miền trong sản xuất theo nhận xét của bạn? – user1007983

4

@ user1007983

Không, trong sản xuất, thử xử lý/catch vẫn còn tồn tại trong Connect/Express. Cách để giải quyết nó là thêm khối try/catch của riêng bạn vào "root" mà sau đó bạn có thể sử dụng để phát ra sự kiện "lỗi" cho miền trước khi kết nối gửi phản hồi lỗi.

try { 
    // .. code here .. 
} catch (err) { 
    domain.emit('error', err); 
} 

Một cách khác để có được xung quanh nó là chỉ cần ngắt kết nối từ xử lý, giống như gói mã của bạn trong một khối setImmediate

0

Tôi đã thử try/catch khối (có thể không hoạt động theo cách bạn nghĩ với async mã). Tôi đã thử các nút tên miền theo nhiều cách khác nhau. Nhưng tôi đã không thể xử lý một ngoại lệ được ném vào một lib bên thứ 3 (phần tiếp theo). Tại sao tôi lại bị ngoại lệ? Vâng, đó là vì SQL được tạo ra không được định dạng tốt. (Lỗi của tôi).

Anywho, giải pháp phù hợp nhất với tôi và dự án (nhỏ) của tôi là sử dụng forever. Hãy để các trường hợp ngoại lệ xảy ra, nhưng hãy kích hoạt lại nút nếu chúng thực hiện. Tôi nghi ngờ nó là giải pháp thanh lịch nhất, nhưng nó hoạt động cho tôi và dự án nhỏ của tôi.

Với một dự án lớn hơn, lĩnh vực kết hợp với clustering API có thể là một lựa chọn tốt.

Winston là một lựa chọn khác. Nó có thể là mát mẻ để kết hợp forever với winston để nếu bạn có được một ngoại lệ, bạn có thể có winston email you, vì vậy bạn có thể sửa mã. Trong khi đó, forever sẽ vui vẻ khởi động lại ứng dụng cho bạn.

0

Tôi đã gặp phải vấn đề này trong khi kiểm tra xử lý lỗi dựa trên miền của tôi.

Tôi đã đi theo phương pháp được đề xuất ở đây bởi Issac, với một vài thay đổi nhỏ: sử dụng 'domain.active' để nhận miền hiện hoạt và phát ra sự kiện lỗi trên đó và tôi đã sử dụng hàm bao hàm để tránh gặp sửa đổi tất cả các chức năng xử lý của tôi:

domainWrapper = function(func) { 
    return function(req, res) { 
     try { 
      return func(req, res); 
     } catch (err) { 
      domain.active.emit('error', err); 
     } 
    } 
} 

Sau đó, thay đổi loại điều này:

app.get('/jobs', handlerFunc); 

này:

app.get('/jobs', domainWrapper(handlerFunc));