Помилка обробки принципів для програм Node.js + Express.js?


177

Схоже, повідомлення про помилки / обробку помилок виконується інакше в додатках Node.js + Express.js порівняно з іншими рамками. Чи правильно я розумію, що вона працює наступним чином?

A) Виявляйте помилки, отримуючи їх як параметри для функцій зворотного дзвінка. Наприклад:

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

B) Повідомте про помилки в MIDDLEWARE, зателефонувавши на наступний (помилка). Приклад:

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

C) Повідомте про помилки в маршрутах, кинувши помилку. Приклад:

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

D) Ручка помилки при налаштуванні власного обробника помилок з допомогою app.error () або використовувати загальний обробник помилок Connect. Приклад:

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

Чи є ці чотири принципи основою для всіх помилок / звітування про помилки в додатках Node.js + Express.js?

Відповіді:


183

Помилка обробки в Node.js, як правило, формату A). Більшість зворотних викликів повертають об'єкт помилки як перший аргумент або null.

Express.js використовує проміжне програмне забезпечення, а синтаксис середнього програмного забезпечення використовує B) та E) (згадані нижче).

В) це погана практика, якщо ви запитаєте мене.

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

Ви можете легко переписати вище, як

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

Синтаксис середнього програмного забезпечення дійсний у getзапиті.

Що стосується D)

(19:26:37 PM) tjholowaychuk: app.error видалено в 3.x

TJ щойно підтвердив, що app.errorзастаріло на користь Е

Е)

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

Будь-яке середнє програмне забезпечення, яке має довжину 4 (4 аргументи), вважається програмним забезпеченням помилки. Коли один дзвінок next(err)підключається, переходить і викликає проміжне програмне забезпечення на основі помилок.


11
Дякую! Для кожного, хто може зіткнутися з цим у майбутньому, схоже, порядок парам "метод e" насправді помилка, req, res, next (замість req, res, next, err).
Клінт Харріс

9
Отже, це виглядає чудово, але проблема, яку я бачу, полягає в тому, що деякі помилки ніколи не пробиваються до описаних вами оброблювачів помилок, і їх може спіймати лише обробник process.on ('uncaughtException', fn). Загальноприйнята мудрість полягає в тому, щоб це не сталося і покладатися на Forever або подібне, щоб перезапустити додаток, але якщо ви це зробите, як повернути дружню сторінку помилки?
Пол

1
@chovy Також просто фій. Оброблювач помилок повинен бути наданий додатку після помилки кинутого / наступного. Якщо це буде раніше, помилка не сприймає.
Лі Олайвар

3
Наступна (помилка) - це по суті версія Express про викидання помилки, вам потрібно явно викликати її всередині власного проміжного програмного забезпечення
qodeninja,

1
@qodeninja Цей метод вважається найкращою практикою в Express.
Девід Оліверос

11

Люди Joyent опублікували справді проникливий документ про найкращі практики щодо цього. Стаття, необхідна для читання для будь-якого розробника Node.js.



Чудова стаття, зафіксувала посилання, щоб вказати на оновлений документ Joyent.
stephbu

2
стаття непогана: але занадто багато тексту та недостатньо прикладів, це стаття для справжніх професіоналів
Герд

3

Чому перший параметр?

Через асинхронну природу Node.js, шаблон першого параметра як помилка став добре утвердженим як умова для обробки помилок Node.js userland . Це тому, що асинхронний:

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

Таким чином, замість того, щоб мати перший аргумент зворотного дзвінка - це єдиний розумний спосіб передавати помилки асинхронно, крім того, щоб просто їх викидати.

Якщо це зробити, це призведе до того, unhandled exceptionщо, як тільки це звучить, означає, що нічого не було зроблено для виходу програми із заплутаного стану.

Винятки, чому вони існують

Однак варто зазначити, що практично вся частина Node.js є випромінювачем подій, і викид виключення - це подія низького рівня, яку можна обробляти, як і всі події:

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

Це можна, але не слід сприймати до крайності, щоб зрозуміти всі помилки та зробити програму, яка дуже намагатиметься ніколи не виходити з ладу . Це жахлива ідея майже в кожному випадку використання, оскільки вона не залишить розробника без уявлення про те, що відбувається в стані програми, і є аналогом обгортці основного в try-catch.

Домени - групування подій логічно

У рамках вирішення цієї проблеми винятків, завдяки яким програми перепадають, домени дозволяють розробнику взяти, наприклад, програму Express.js, і спробувати розумно відключити з'єднання у випадку катастрофічного збою.

ES6

Це, мабуть, згадує, що це знову зміниться, оскільки ES6 дозволяє схемі генератора створювати асинхронні події, які все ще підлягають пошуку за допомогою блоків спробу / лову.

Коа (написано Т. Дж. Головайчуком, тим самим оригінальним автором Express.js) помітно це робить. Він використовує yieldоператор ES6 для створення блоків, які, хоча і виглядають майже синхронними, обробляються у звичайному асинхронному вузлі:

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

Цей приклад був безсоромно викрадений звідси .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.