Подтвердить что ты не робот

Как обрабатывать исключения кода в node.js?

Я просмотрел документацию Express, и часть, описывающая обработку ошибок, полностью непрозрачна для меня.

Я понял, что app они имеют в виду экземпляр createServer(), правильно? Но я не знаю, как остановить node.js от раздувания процесса приложения, когда во время обработки запроса возникает исключение.

Мне действительно ничего не нужно; Я просто хочу вернуть статус 500, плюс пустой ответ, когда есть исключение. Процесс node не должен завершаться только потому, что где-то было неотображенное исключение.

Есть ли простой пример того, как достичь этого?


var express = require('express');
var http = require('http');

var app = express.createServer();

app.get('/', function(req, res){
    console.log("debug", "calling")
    var options = {
        host: 'www.google.com',
        port: 80,
        path: "/"
    };
    http.get(options, function(response) {
       response.on("data", function(chunk) {
           console.log("data: " + chunk);
           chunk.call(); // no such method; throws here
       });
    }).on('error', function(e) {
       console.log("error connecting" + e.message);
    });
});

app.configure(function(){
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.listen(3000);

сбой всего приложения, создание трассировки

mypath/tst.js:16
           chunk.call(); // no such method; throws here
                 ^ TypeError: Object ... has no method 'call'
    at IncomingMessage.<anonymous> (/Library/WebServer/Documents/discovery/tst.js:16:18)
    at IncomingMessage.emit (events.js:67:17)
    at HTTPParser.onBody (http.js:115:23)
    at Socket.ondata (http.js:1150:24)
    at TCP.onread (net.js:374:27)
4b9b3361

Ответ 1

Если вы действительно хотите поймать все исключения и предоставить некоторую обработку, отличную от выхода из процесса Node.js, вам нужно обработать Node uncaughtException событие.

Если вы думаете об этом, это Node вещь, а не вещь Express, потому что если вы выбросите исключение из какой-либо произвольной части кода, то нет гарантии, что Express может или когда-нибудь ее увидит, или будет положение, чтобы заманить его в ловушку. (Почему? Исключения не очень хорошо взаимодействуют с асинхронным кодом обратного вызова, управляемым событиями, который является стилем Node. Исключения перемещаются вверх по стеку вызовов, чтобы найти блок catch(), который в области на момент генерирования исключения. myFunction откладывает некоторую работу на функцию обратного вызова, которая запускается, когда происходит какое-либо событие, а затем возвращается к циклу событий, а затем, когда эта функция обратного вызова вызывается, она вызывается непосредственно из цикла основного события, а myFunction больше не находится на стек вызовов, если эта функция обратного вызова генерирует исключение, даже если myFunction имеет блок try/catch, он не поймает исключение.)

На практике это означает, что если вы выбросите исключение и не поймаете его самостоятельно, и вы сделаете это в функции, которая была непосредственно вызвана Express, Express может поймать исключение и вызвать обработчик ошибок, который вы установили, предполагая, что вы настроили часть промежуточного программного обеспечения обработки ошибок, например app.use(express.errorHandler()). Но если вы выкинете одно и то же исключение в функцию, вызванную в ответ на асинхронное событие, Express не сможет ее поймать. (Единственный способ поймать его - прослушивать глобальное событие Node uncaughtException, что было бы плохой идеей, прежде всего потому, что это глобально, и вам может понадобиться использовать его для других вещей, а во-вторых, потому что Express не будет идея, какой запрос был связан с исключением.)

Вот пример. Я добавляю этот фрагмент кода обработки маршрута в существующее приложение Express:

app.get('/fail/sync', function(req, res) {
   throw new Error('whoops');
});
app.get('/fail/async', function(req, res) {
   process.nextTick(function() {
      throw new Error('whoops');
   });
});

Теперь, если я посещаю http://localhost:3000/fail/sync в своем браузере, браузер удаляет стек вызовов (показывая express.errorHandler в действии). Однако, если я посещаю http://localhost:3000/fail/async в браузере, браузер злится (Chrome показывает "Нет данных: Ошибка 324, net:: ERR_EMPTY_RESPONSE: сервер закрыл соединение без отправки каких-либо данных" ), поскольку Node завершил процесс, показывая обратную трассировку на stdout в терминале, где я его вызывал.

Ответ 2

Чтобы улавливать асинхронные ошибки, я использую домен. С помощью Express вы можете попробовать этот код:

function domainWrapper() {
    return function (req, res, next) {
        var reqDomain = domain.create();
        reqDomain.add(req);
        reqDomain.add(res);

        res.on('close', function () {
            reqDomain.dispose();
        });
        reqDomain.on('error', function (err) {
            next(err);            
        });
        reqDomain.run(next)
    }
}
app.use(domainWrapper());
//all your other app.use
app.use(express.errorHandler());

Этот код сделает вашу асинхронную ошибку захваченной и отправленной на ваш обработчик ошибок. В этом примере я использую express.errorHandler, но он работает с любым обработчиком.

Дополнительные сведения о домене: http://nodejs.org/api/domain.html

Ответ 3

Вы можете использовать обработчик ошибок по умолчанию, который выражает использование, которое на самом деле connect обработчик ошибок.

var app = require('express').createServer();

app.get('/', function(req, res){
  throw new Error('Error thrown here!');
});

app.configure(function(){
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.listen(3000);

Обновление Для вашего кода вам действительно нужно зафиксировать ошибку и передать ее, чтобы выразить это как

var express = require('express');
var http = require('http');

var app = express.createServer();

app.get('/', function (req, res, next) {
  console.log("debug", "calling");
  var options = {
    host:'www.google.com',
    port:80,
    path:"/"
  };
  http.get(options,
    function (response) {
      response.on("data", function (chunk) {
        try {
          console.log("data: " + chunk);
          chunk.call(); // no such method; throws here

        }
        catch (err) {
          return next(err);
        }
      });
    }).on('error', function (e) {
      console.log("error connecting" + e.message);
    });
});

app.configure(function () {
  app.use(express.errorHandler({ dumpExceptions:true, showStack:true }));
});

app.listen(3000);