Nguyên tắc xử lý lỗi cho các ứng dụng Node.js + Express.js?


177

Có vẻ như báo cáo / xử lý lỗi được thực hiện khác nhau trong các ứng dụng Node.js + Express.js so với các khung công tác khác. Tôi có đúng khi hiểu rằng nó hoạt động như sau?

A) Phát hiện lỗi bằng cách nhận chúng dưới dạng tham số cho các hàm gọi lại của bạn. Ví dụ:

doSomethingAndRunCallback(function(err) { 
    if(err) {  }
});

B) Báo cáo lỗi trong PHẦN MỀM bằng cách gọi tiếp theo (err). Thí dụ:

handleRequest(req, res, next) {
    // An error occurs…
    next(err);
}

C) Báo cáo lỗi trong ROUTES bằng cách ném lỗi. Thí dụ:

app.get('/home', function(req, res) {
    // An error occurs
    throw err;
});

D) Xử lý lỗi bằng cách định cấu hình trình xử lý lỗi của riêng bạn thông qua app.error () hoặc sử dụng trình xử lý lỗi Connect chung. Thí dụ:

app.error(function(err, req, res, next) {
    console.error(err);
    res.send('Fail Whale, yo.');
});

Bốn nguyên tắc này có phải là cơ sở cho tất cả các xử lý / báo cáo lỗi trong các ứng dụng Node.js + Express.js không?

Câu trả lời:


183

Xử lý lỗi trong Node.js thường có định dạng A). Hầu hết các cuộc gọi lại trả về một đối tượng lỗi là đối số đầu tiên hoặc null.

Express.js sử dụng phần mềm trung gian và cú pháp phần mềm trung gian sử dụng B) và E) (được đề cập bên dưới).

C) là thực hành xấu nếu bạn hỏi tôi.

app.get('/home', function(req, res) {
    // An error occurs
    throw err;
});

Bạn có thể dễ dàng viết lại như trên

app.get('/home', function(req, res, next) {
    // An error occurs
    next(err);
});

Cú pháp Middleware là hợp lệ trong một getyêu cầu.

Đối với D)

(07:26:37 PM) tjholowaychuk: app.error bị xóa trong 3.x

TJ chỉ xác nhận rằng app.errorkhông được ủng hộ E

E)

app.use(function(err, req, res, next) {
  // Only handle `next(err)` calls
});

Bất kỳ phần mềm trung gian nào có độ dài 4 (4 đối số) đều được coi là phần mềm trung gian lỗi. Khi một cuộc gọi next(err)kết nối đi và gọi phần mềm trung gian dựa trên lỗi.


11
Cảm ơn! Đối với bất kỳ ai có thể gặp phải điều này trong tương lai, có vẻ như thứ tự của params cho "phương thức e" thực sự là err, req, res, next (thay vì req, res, next, err).
Clint Harris

9
Vì vậy, điều này có vẻ tuyệt vời, nhưng một vấn đề tôi đang gặp phải là một số lỗi không bao giờ chuyển sang trình xử lý lỗi mà bạn mô tả và chỉ có thể được xử lý bởi trình xử lý process.on ('unsaughtException', fn). Sự khôn ngoan thông thường là để điều đó xảy ra và dựa vào Mãi mãi hoặc muốn khởi động lại ứng dụng, nhưng nếu bạn làm điều đó, làm thế nào để bạn trả lại một trang lỗi thân thiện?
Paul

1
@chovy Ngoài ra, chỉ là một fyi. Trình xử lý lỗi phải được cung cấp cho ứng dụng sau lỗi ném / tiếp theo. Nếu là trước đó, nó sẽ không bắt lỗi.
Lee Olayvar

3
next (err) về cơ bản là phiên bản ném lỗi của Express, bạn phải gọi nó một cách rõ ràng trong phần mềm trung gian của riêng bạn
qodeninja

1
@qodeninja Phương pháp đó được coi là cách thực hành tốt nhất trong Express.
David Oliveros

11

Những người ở Joyent đã xuất bản một tài liệu thực hành tốt nhất sâu sắc về điều này. Một bài viết phải đọc cho bất kỳ nhà phát triển Node.js.



Bài viết tuyệt vời, đã sửa liên kết để trỏ đến tài liệu cập nhật của Joyent.
stephbu

2
Bài viết không tệ: nhưng quá nhiều văn bản và không đủ ví dụ, đó là một bài viết dành cho các chuyên gia thực sự
Gerd

3

Tại sao tham số đầu tiên?

Do tính chất không đồng bộ của Node.js, mẫu tham số lỗi đầu tiên đã được thiết lập tốt như một quy ước để xử lý lỗi Node.js của người dùng . Điều này là do không đồng bộ:

try {
    setTimeout(function() {
        throw 'something broke' //Some random error
    }, 5)
}
catch(e) {
   //Will never get caught
}

Vì vậy, thay vì có đối số đầu tiên của cuộc gọi lại gần như là cách hợp lý duy nhất để vượt qua các lỗi không đồng bộ ngoài việc chỉ ném chúng.

Làm như vậy sẽ dẫn đến kết quả là unhandled exception, theo cách mà nó phát ra, ngụ ý rằng không có gì được thực hiện để đưa ứng dụng ra khỏi trạng thái bối rối của nó.

Ngoại lệ, tại sao chúng tồn tại

Tuy nhiên, điều đáng chú ý là hầu như tất cả các phần của Node.js đều là trình phát sự kiện và việc ném ngoại lệ là một sự kiện cấp thấp có thể được xử lý như tất cả các sự kiện:

//This won't immediately crash if connection fails
var socket = require("net").createConnection(5000);
socket.on("error", function(err) {
    console.error("calm down...", err)
});

Điều này có thể nhưng không nên được đưa đến mức cực đoan để bắt tất cả các lỗi và tạo một ứng dụng sẽ rất cố gắng để không bao giờ gặp sự cố. Đây là một ý tưởng tồi tệ trong gần như mọi trường hợp sử dụng, bởi vì nó sẽ khiến nhà phát triển không có ý tưởng gì về những gì đang diễn ra trong trạng thái ứng dụng và tương tự như gói chính trong thử bắt.

Tên miền - nhóm sự kiện hợp lý

Là một phần trong việc xử lý vấn đề ngoại lệ này khiến các ứng dụng bị đổ, các miền cho phép nhà phát triển lấy, ví dụ như ứng dụng Express.js và thử và tắt các kết nối một cách hợp lý trong trường hợp thất bại thảm hại.

ES6

Có thể đề cập rằng điều này sẽ thay đổi một lần nữa vì ES6 cho phép mẫu máy phát tạo các sự kiện không đồng bộ vẫn có thể bắt được với các khối thử / bắt.

Koa (được viết bởi TJ Holowaychuck, cùng tác giả ban đầu của Express.js) đáng chú ý thực hiện điều này. Nó sử dụng yieldcâu lệnh ES6 để tạo các khối, trong khi xuất hiện gần như đồng bộ hóa, được xử lý theo kiểu không đồng bộ nút thông thường:

app.use(function *(next) {
    try {
        yield next;
    } 
    catch (err) {
        this.status = err.status || 500;
        this.body = err.message;
        this.app.emit('error', err, this);
    }
});

app.use(function *(next) {
    throw new Error('some error');
})

Ví dụ này đã bị đánh cắp một cách đáng xấu hổ từ đây .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.