Prinsip penanganan kesalahan untuk aplikasi Node.js + Express.js?

177

Sepertinya pelaporan kesalahan / penanganan dilakukan secara berbeda di aplikasi Node.js + Express.js dibandingkan dengan kerangka kerja lainnya. Apakah saya benar dalam memahami bahwa itu berfungsi sebagai berikut?

A) Mendeteksi kesalahan dengan menerimanya sebagai parameter untuk fungsi panggilan balik Anda. Sebagai contoh:

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

B) Laporkan kesalahan dalam MIDDLEWARE dengan memanggil next (err). Contoh:

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

C) Laporkan kesalahan dalam ROUTES dengan melemparkan kesalahan. Contoh:

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

D) Menangani kesalahan dengan mengkonfigurasi penangan kesalahan Anda sendiri melalui app.error () atau menggunakan penangan kesalahan Connect generik. Contoh:

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

Apakah keempat prinsip ini menjadi dasar untuk semua penanganan / pelaporan kesalahan dalam aplikasi Node.js + Express.js?

Clint Harris
sumber

Jawaban:

183

Menangani kesalahan di Node.js umumnya dari format A). Sebagian besar panggilan balik mengembalikan objek kesalahan sebagai argumen pertama atau null.

Express.js menggunakan middleware dan sintaks middleware menggunakan B) dan E) (disebutkan di bawah).

C) adalah praktik buruk jika Anda bertanya kepada saya.

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

Anda dapat dengan mudah menulis ulang di atas sebagai

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

Sintaks Middleware valid dalam getpermintaan.

Adapun D)

(07:26:37 PM) tjholowaychuk: app.error dihapus dalam 3.x

TJ baru saja mengkonfirmasi bahwa app.erroritu ditinggalkan demi E

E)

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

Setiap middleware yang memiliki panjang 4 (4 argumen) dianggap sebagai middleware kesalahan. Ketika satu panggilan next(err)terhubung, panggilan dan panggilan middleware berbasis kesalahan.

Raynos
sumber
11
Terima kasih! Bagi siapa pun yang mungkin menemukan ini di masa depan, sepertinya urutan params untuk "metode e" sebenarnya adalah err, req, res, next (bukan req, res, next, err).
Clint Harris
9
Jadi ini terlihat hebat, tetapi masalah yang saya lihat adalah bahwa beberapa kesalahan tidak pernah sampai pada penangan kesalahan yang Anda gambarkan, dan hanya dapat ditangkap oleh suatu proses.pada penangan (uncaughtException ', fn). Kebijaksanaan konvensional adalah membiarkan hal itu terjadi dan mengandalkan Forever atau sejenisnya untuk memulai ulang aplikasi, tetapi jika Anda melakukannya, bagaimana Anda mengembalikan halaman kesalahan ramah?
Paul
1
@ Chovy Juga, hanya fyi. Penangan kesalahan harus diberikan ke aplikasi setelah kesalahan yang dilemparkan / berikutnya. Jika sebelumnya, tidak akan menemukan kesalahan.
Lee Olayvar
3
next (err) pada dasarnya adalah versi Express untuk melempar kesalahan, Anda harus secara eksplisit menyebutnya di dalam middleware Anda sendiri
qodeninja
1
@qodeninja Metode itu dianggap praktik terbaik di Express.
David Oliveros
11

Orang-orang di Joyent telah menerbitkan dokumen praktik terbaik yang sangat mendalam tentang hal ini. Artikel yang harus dibaca untuk setiap pengembang Node.js.

hthserhs
sumber
Artikel bagus, perbaiki tautan untuk menunjuk ke dokumen Joyent yang diperbarui.
stephbu
2
artikel tidak buruk: tetapi terlalu banyak teks dan tidak cukup contoh, ini adalah artikel untuk profesional sejati
Gerd
3

Mengapa parameter pertama?

Karena sifat asinkron Node.js, pola parameter-pertama-sebagai-err telah menjadi mapan sebagai konvensi untuk penanganan kesalahan Node.js userland . Ini karena asinkron:

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

Jadi alih-alih memiliki argumen pertama tentang callback adalah satu-satunya cara yang masuk akal untuk melewatkan kesalahan secara tidak sinkron selain hanya melemparkannya.

Melakukannya akan menghasilkan sesuatu unhandled exceptionyang, hanya dengan cara bunyinya, menyiratkan bahwa tidak ada yang dilakukan untuk mendapatkan aplikasi keluar dari keadaan bingung.

Pengecualian, mengapa mereka ada

Namun perlu dicatat, bahwa hampir semua bagian dari Node.js adalah penghasil peristiwa dan melemparkan pengecualian adalah peristiwa tingkat rendah yang dapat ditangani seperti semua peristiwa:

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

Ini bisa-tetapi-tidak boleh dibawa ke ekstrem untuk menangkap semua kesalahan dan membuat aplikasi yang akan berusaha sangat keras untuk tidak pernah crash. Ini adalah ide yang mengerikan di hampir setiap kasus penggunaan, karena hal itu akan membuat pengembang tanpa tahu apa yang terjadi dalam keadaan aplikasi dan analog dengan membungkus utama dalam try-catch.

Domains - mengelompokkan acara secara logis

Sebagai bagian dari penanganan masalah pengecualian ini yang membuat aplikasi jatuh, domain memungkinkan pengembang untuk mengambil, misalnya aplikasi Express.js, dan mencoba dan menutup koneksi secara masuk akal jika terjadi kegagalan yang dahsyat.

ES6

Mungkin menyebutkan bahwa ini akan berubah lagi karena ES6 memungkinkan pola generator untuk membuat peristiwa asinkron yang masih dapat ditangkap dengan blok coba / tangkap.

Koa (ditulis oleh TJ Holowaychuck, penulis asli yang sama dari Express.js) terlihat melakukan hal ini. Ini menggunakan yieldpernyataan ES6 untuk membuat blok yang, meskipun tampak hampir sinkron, ditangani dalam mode asinkron simpul biasa:

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');
})

Contoh ini dicuri tanpa malu-malu dari sini .

David
sumber