Обработка ошибок node js express

Обработка ошибок

Функции промежуточного обработчика для обработки ошибок определяются так же, как и другие функции промежуточной обработки, но с указанием для функции обработки ошибок не трех, а четырех аргументов: (err, req, res, next). Например:


app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

Промежуточный обработчик для обработки ошибок должен быть определен последним, после указания всех app.use() и вызовов маршрутов; например:


var bodyParser = require('body-parser');
var methodOverride = require('method-override');

app.use(bodyParser());
app.use(methodOverride());
app.use(function(err, req, res, next) {
  // logic
});

Ответы, поступающие из функции промежуточной обработки, могут иметь любой формат, в зависимости от ваших предпочтений. Например, это может быть страница сообщения об ошибке HTML, простое сообщение или строка JSON.

В целях упорядочения (и для фреймворков более высокого уровня) можно определить несколько функций промежуточной обработки ошибок, точно так же, как это допускается для обычных функций промежуточной обработки. Например, для того чтобы определить обработчик ошибок для запросов, совершаемых с помощью XHR, и для остальных запросов, можно воспользоваться следующими командами:


var bodyParser = require('body-parser');
var methodOverride = require('method-override');

app.use(bodyParser());
app.use(methodOverride());
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);

В данном примере базовый код logErrors может записывать информацию о запросах и ошибках в stderr, например:


function logErrors(err, req, res, next) {
  console.error(err.stack);
  next(err);
}

Кроме того, в данном примере clientErrorHandler определен, как указано ниже; в таком случае ошибка явным образом передается далее следующему обработчику:


function clientErrorHandler(err, req, res, next) {
  if (req.xhr) {
    res.status(500).send({ error: 'Something failed!' });
  } else {
    next(err);
  }
}

“Обобщающая” функция errorHandler может быть реализована так:


function errorHandler(err, req, res, next) {
  res.status(500);
  res.render('error', { error: err });
}

При передаче какого-либо объекта в функцию next() (кроме строки 'route'), Express интерпретирует текущий запрос как ошибку и пропустит все остальные функции маршрутизации и промежуточной обработки, не являющиеся функциями обработки ошибок. Для того чтобы обработать данную ошибку определенным образом, необходимо создать маршрут обработки ошибок, как описано в следующем разделе.

Если задан обработчик ошибок с несколькими функциями обратного вызова, можно воспользоваться параметром route, чтобы перейти к следующему обработчику маршрута. Например:


app.get('/a_route_behind_paywall',
  function checkIfPaidSubscriber(req, res, next) {
    if(!req.user.hasPaid) {

      // continue handling this request
      next('route');
    }
  }, function getPaidContent(req, res, next) {
    PaidContent.find(function(err, doc) {
      if(err) return next(err);
      res.json(doc);
    });
  });

В данном примере обработчик getPaidContent будет пропущен, но выполнение всех остальных обработчиков в app для /a_route_behind_paywall будет продолжено.

Вызовы next() и next(err) указывают на завершение выполнения текущего обработчика и на его состояние. next(err) пропускает все остальные обработчики в цепочке, кроме заданных для обработки ошибок, как описано выше.

Стандартный обработчик ошибок

В Express предусмотрен встроенный обработчик ошибок, который обрабатывает любые возможные ошибки, встречающиеся в приложении. Этот стандартный обработчик ошибок добавляется в конец стека функций промежуточной обработки.

В случае передачи ошибки в next() без обработки с помощью обработчика ошибок, такая ошибка будет обработана встроенным обработчиком ошибок. Ошибка будет записана на клиенте с помощью трассировки стека. Трассировка стека не включена в рабочую среду.

Для запуска приложения в рабочем режиме необходимо задать для переменной среды NODE_ENV значение production.

При вызове next() с ошибкой после начала записи ответа
(например, если ошибка обнаружена во время включения ответа в поток, направляемый клиенту), стандартный обработчик ошибок Express закрывает соединение и отклоняет запрос.

Поэтому при добавлении нестандартного обработчика ошибок вам потребуется делегирование в стандартные
механизмы обработки ошибок в Express в случае, если заголовки уже были отправлены клиенту:


function errorHandler(err, req, res, next) {
  if (res.headersSent) {
    return next(err);
  }
  res.status(500);
  res.render('error', { error: err });
}

Время на прочтение
7 мин

Количество просмотров 24K

Когда я только начинал работать с Express и пытался разобраться с тем, как обрабатывать ошибки, мне пришлось нелегко. Возникало такое ощущение, будто никто не писал о том, что мне было нужно. В итоге мне пришлось самому искать ответы на мои вопросы. Сегодня я хочу рассказать всё, что знаю об обработке ошибок в Express-приложениях. Начнём с синхронных ошибок.

Обработка синхронных ошибок

Если вам нужно обработать синхронную ошибку, то вы можете, для начала, с помощью инструкции throw, выдать такую ошибку в обработчике запроса Express. Обратите внимание на то, что обработчики запросов ещё называют «контроллерами», но я предпочитаю использовать термин «обработчик запросов» так как он кажется мне понятнее.

Вот как это выглядит:

app.post('/testing', (req, res) => {
  throw new Error('Something broke! ')
})

Такие ошибки можно перехватить с помощью обработчика ошибок Express. Если вы не написали собственный обработчик ошибок (подробнее об этом мы поговорим ниже), то Express обработает ошибку с помощью обработчика, используемого по умолчанию.

Вот что делает стандартный обработчик ошибок Express:

  1. Устанавливает код состояния HTTP-ответа в значение 500.
  2. Отправляет сущности, выполнившей запрос, текстовый ответ.
  3. Логирует текстовый ответ в консоль.

Сообщение об ошибке, выведенное в консоль

Обработка асинхронных ошибок

Для обработки асинхронных ошибок нужно отправить ошибку обработчику ошибок Express через аргумент next:

app.post('/testing', async (req, res, next) => {
  return next(new Error('Something broke again! '))
})

Вот что попадёт в консоль при логировании этой ошибки.

Сообщение об ошибке, выведенное в консоль

Если вы пользуетесь в Express-приложении конструкцией async/await, то вам понадобится использовать функцию-обёртку, наподобие express-async-handler. Это позволяет писать асинхронный код без блоков try/catch. Подробнее об async/await в Express можно почитать здесь.

const asyncHandler = require('express-async-handler')

app.post('/testing', asyncHandler(async (req, res, next) => {
  // Сделать что-нибудь
}))

После того, как обработчик запроса обёрнут в express-async-handler, то можно, так же, как было описано выше, выбросить ошибку с использованием инструкции throw. Эта ошибка попадёт к обработчику ошибок Express.

app.post('/testing', asyncHandler(async (req, res, next) => {
  throw new Error('Something broke yet again! ')
}))

Сообщение об ошибке, выведенное в консоль

Написание собственного обработчика ошибок

Обработчики ошибок Express принимают 4 аргумента:

  1. error
  2. req
  3. res
  4. next

Размещать их нужно после промежуточных обработчиков и маршрутов.

app.use(/*...*/)
app.get(/*...*/)
app.post(/*...*/)
app.put(/*...*/)
app.delete(/*...*/)

// Собственный обработчик ошибок нужно поместить после всех остальных промежуточных обработчиков
app.use((error, req, res, next) => { /* ... */ })

Если создать собственный обработчик ошибок, то Express прекратит использование стандартного обработчика. Для того чтобы обработать ошибку, нужно сформировать ответ для фронтенд-приложения, которое обратилось к конечной точке, в которой возникла ошибка. Это означает, что нужно выполнить следующие действия:

  1. Сформировать и отправить подходящий код состояния ответа.
  2. Сформировать и отправить подходящий ответ.

То, какой именно код состояния подойдёт в каждом конкретном случае, зависит от того, что именно произошло. Вот список типичных ошибок, к обработке которых вы должны быть готовы:

  1. Ошибка 400 Bad Request. Используется в двух ситуациях. Во-первых — тогда, когда пользователь не включил в запрос необходимое поле (например — в отправленной платёжной форме не заполнено поле со сведениями о кредитной карте). Во-вторых — тогда, когда в запросе содержатся некорректные данные (например — ввод в поле пароля и в поле подтверждения пароля разных паролей).
  2. Ошибка 401 Unauthorized. Этот код состояния ответа применяется в том случае, если пользователь ввёл неправильные учётные данные (вроде имени пользователя, адреса электронной почты или пароля).
  3. Ошибка 403 Forbidden. Используется в тех случаях, когда пользователю не разрешён доступ к конечной точке.
  4. Ошибка 404 Not Found. Применяется в тех случаях, когда конечную точку невозможно обнаружить.
  5. Ошибка 500 Internal Server Error. Применяется тогда, когда запрос, отправленный фронтендом, сформирован правильно, но на бэкенде при этом возникла какая-то ошибка.

После того, как определён подходящий код состояния ответа, его нужно установить с помощью res.status:

app.use((error, req, res, next) => {
  // Ошибка, выдаваемая в ответ на неправильно сформированный запрос
  res.status(400)
  res.json(/* ... */)
})

Код состояния ответа должен соответствовать сообщению об ошибке. Для этого нужно отправлять код состояния вместе с ошибкой.

Легче всего это сделать с помощью пакета http-errors. Он позволяет отправлять в ошибке три фрагмента информации:

  1. Код состояния ответа.
  2. Сообщение, сопутствующее ошибке.
  3. Любые данные, которые нужно отправить (это необязательно).

Вот как установить пакет http-errors:

npm install http-errors --save

Вот как этим пакетом пользоваться:

const createError = require('http-errors')

// Создание ошибки
throw createError(status, message, properties)

Рассмотрим пример, который позволит как следует в этом всём разобраться.

Представим, что мы пытаемся обнаружить пользователя по адресу его электронной почты. Но этого пользователя найти не удаётся. В результате мы решаем отправить в ответ на соответствующий запрос ошибку User not found, сообщающую вызывающей стороне о том, что пользователь не найден.

Вот что нам нужно будет сделать при создании ошибки:

  1. Установить код состояния ответа как 400 Bad Request (ведь пользователь ввёл неправильные данные). Это будет наш первый параметр.
  2. Отправить вызывающей стороне сообщение наподобие User not found. Это будет второй параметр.

app.put('/testing', asyncHandler(async (req, res) => {
  const { email } = req.body
  const user = await User.findOne({ email })

  // Если пользователь не найден - выбросим ошибку
  if (!user) throw createError(400, `User '${email}' not found`)
}))

Получить код состояния можно с помощью конструкции error.status, а сообщение ошибки — с помощью error.message:

// Логирование ошибки
app.use((error, req, res, next) => {
  console.log('Error status: ', error.status)
  console.log('Message: ', error.message)
})

Результат логирования ошибки в консоли

Затем состояние ответа устанавливают с помощью res.status, а сообщение записывают в res.json:

app.use((error, req, res, next) => {
  // Установка кода состояния ответа
  res.status(error.status)

  // Отправка ответа
  res.json({ message: error.message })
})

Лично я предпочитаю отправлять в подобных ответах код состояния, сообщение и результат трассировки стека. Это облегчает отладку.

app.use((error, req, res, next) => {
  // Установка кода состояния ответа
  res.status(error.status)

  // Отправка ответа
  res.json({
    status: error.status,
    message: error.message,
    stack: error.stack
  })
})

▍Код состояния ответа, используемый по умолчанию

Если источником ошибки не является createError, то у неё не будет свойства status. Вот пример, в котором сделана попытка прочесть несуществующий файл с помощью fs.readFile:

const fs = require('fs')
const util = require('util')

// Преобразуем readFile из функции, использующей коллбэки, в async/await-функцию.
// Подробности об этом смотрите здесь: https://zellwk.com/blog/callbacks-to-promises
const readFilePromise = util.promisify(fs.readFile)

app.get('/testing', asyncHandler(async (req, res, next) => {
  const data = await readFilePromise('some-file')
})

У такого объекта ошибки не будет свойства status:

app.use((error, req, res, next) => {
  console.log('Error status: ', error.status)
  console.log('Message: ', error.message)
})

Результат логирования ошибки в консоли

В подобных случаях можно задать код ошибки, используемый по умолчанию. А именно, речь идёт об ошибке 500 Internal Server Error:

app.use((error, req, res, next) => {
  res.status(error.status || 500)
  res.json({
    status: error.status,
    message: error.message,
    stack: error.stack
  })
})

▍Изменение кода состояния ошибки

Предположим, мы собираемся прочитать некий файл, воспользовавшись данными, предоставленными пользователем. Если такого файла не существует, это значит, что нам нужно выдать ошибку 400 Bad Request. Ведь в том, что файл найти не удаётся, нет вины сервера.

В подобном случае нужно воспользоваться конструкцией try/catch для перехвата исходной ошибки. Затем нужно воссоздать объект ошибки с помощью createError:

app.get('/testing', asyncHandler(async (req, res, next) => {
  try {
    const { file } = req.body
    const contents = await readFilePromise(path.join(__dirname, file))
  } catch (error) {
    throw createError(400, `File ${file} does not exist`)
  }
})

▍Обработка ошибок 404

Если запрос прошёл через все промежуточные обработчики и маршруты, но так и не был обработан, это означает, что конечная точка, соответствующая такому запросу, не была найдена.

Для обработки ошибок 404 Not Found нужно добавить, между маршрутами и обработчиком ошибок, дополнительный обработчик. Вот как выглядит создание объекта ошибки 404:

// Промежуточные обработчики...
// Маршруты...

app.use((req, res, next) => {
  next(createError(404))
})

// Обработчик ошибок...

Сведения об ошибке

▍Замечания об ошибке ERR_HTTP_HEADERS_SENT

Не впадайте в панику если видите сообщение об ошибке ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client. Она возникает из-за того, что в одном и том же обработчике многократно вызывается метод, устанавливающий заголовки ответа. Вот методы, вызов которых приводит к автоматической установке заголовков ответа:

  1. res.send
  2. res.json
  3. res.render
  4. res.sendFile
  5. res.sendStatus
  6. res.end
  7. res.redirect

Так, например, если вы вызовете методы res.render и res.json в одном и том же обработчике ответа, то вы получите ошибку ERR_HTTP_HEADERS_SENT:

app.get('/testing', (req, res) => {
  res.render('new-page')
  res.json({ message: '¯\_(ツ)_/¯' })
})

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

▍Обработка ошибок и потоковая передача данных

Если что-то идёт не так при потоковой передаче ответа фронтенду, то можно столкнуться с той же самой ошибкой ERR_HTTP_HEADERS_SENT.

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

app.use((error, req, res, next) => {
  // Сделать это нужно только в том случае, если ответ передаётся в потоковом режиме
  if (res.headersSent) {
    return next(error)
  }

  // Остальной код обработки ошибок
})

Итоги

Сегодня я рассказал вам всё, что знаю об обработке ошибок в Express. Надеюсь, это поможет вам писать более надёжные Express-приложения.

Уважаемые читатели! Как вы обрабатываете ошибки в своих Node.js-проектах?

Error handling in Express.js refers to the process of capturing and responding to errors that occur during the execution of an Express application. In Express, you can handle errors using middleware functions, which are functions that have access to the request and response objects, as well as the next middleware function in the application’s request-response cycle.

Express has built-in error handling middleware, such as the app.use(function(err, req, res, next) {}) function, which can be used to handle errors that are thrown or passed to the next() function. You can also create your own error-handling middleware functions to handle specific errors in your application.

It’s important to note that in Express, the order of middleware functions is important. Error-handling middleware should be placed at the end of the middleware stack, after all, other middleware functions, so that it can catch any errors that are not handled by the other middleware.

In addition, it’s important to handle errors properly and provide a proper error message to the user, rather than returning stack traces to the client in production.

Reason for using error handling used in express.js:

  • To prevent application crashes: Without error handling, unhandled errors can cause an application to crash, leading to poor user experience and potential data loss. Error handling allows you to capture and respond to errors, preventing them from causing a crash and keeping the application running smoothly.
  • To provide meaningful error messages: Error handling allows you to provide meaningful and user-friendly error messages to your users, rather than leaving them with a blank screen or a default error message. This can help to improve the overall user experience and prevent confusion or frustration.
  • To improve debugging: Error handling allows you to capture and log errors, making it easier to debug your application and identify the root cause of any issues. This can save time and effort when troubleshooting problems with your application.
  • To comply with standards and regulations: Proper error handling is often a requirement for compliance with security standards and regulations. By handling errors correctly, you can ensure that your application meets these standards and regulations.

Ways to Perform Error Handling:

1. Middleware function: Express.js has built-in support for error-handling middleware, which allows you to handle errors that occur during the execution of the application.

Syntax:

app.use(function(error, request, response, next) {
       // Handle the error
       response.status(500).send('Internal Server Error');
});

2. Try-Catch statements: you can use try-catch statements to handle errors that occur within specific blocks of code. This ensures that any errors that occur are caught and handled in a controlled manner.

Syntax:

app.get('/', function (req, res) {
    try {
        // Code that might throw an error
    } catch (error) {
        // Handle the error
        res.status(500).send('Internal Server Error');
    }
});

3. Error logging: You can set up error logging so that any errors that occur during the execution of the application are logged to a file or a database for later analysis.

Syntax:

app.get('/', function (req, res) {
    try {
       throw new Error('Something went wrong');
    } catch (error) {
      console.error(error);
    }
});

Error codes: You can set up error codes for different types of errors that occur during the execution of the application. This makes it easier to identify and handle specific errors.

  • Error codes in Node.js are symbolic values that represent specific types of errors that can occur during the execution of a program. Error codes are usually represented as strings and are used to help identify and categorize different types of errors.
  • For example, the Node.js fs module uses error codes such as ‘ENOENT’ (no such file or directory) or ‘EACCES’ (permission denied) to represent specific types of file system errors.
  • When an error occurs in your Node.js application, you can access the error code by checking the code property of the error object. For example, if you are using the fs.readFile function, you can check the code property of the error object that is passed to the callback to determine the type of error that has occurred.

Example:

const fs = require('fs');

fs.readFile('nonexistent-file.txt', (error, data) => {
    if (error) {
        console.error(error.code);
    } else {
        console.log(data.toString());
    }
});

4. HTTP status codes: You can use HTTP status codes to indicate the type of error that occurred. For example, a status code of 400 (Bad Request) can indicate a validation error, while a status code of 500 (Internal Server Error) can indicate a server-side error.

Syntax:

 const http = require('http');

const server = http.createServer((request, response) => {
  response.statusCode = 200;
  response.end('OK');
});

server.listen(8080);
  • By using any of the above, you can handle errors in a controlled and efficient manner, and ensure that your application is robust and stable.

Let’s see some basic examples and explanations for Error Handling in Express.js:

Example 1: Using a middleware function: You can use a middleware function to handle errors that occur during the execution of an application. The middleware function should have four arguments: error, request, response, and next.

Javascript

const express = require('express');

const app = express();

const errorHandler = (err, req, res, next) => {

    console.error(err.stack);

    res.status(500).send('Something went wrong!');

};

app.use((req, res, next) => {

    throw new Error('Something broke!');

});

app.use(errorHandler);

app.listen(3000, () => {

    console.log('App is listening on port 3000');

});

Steps to run the application: Write the below code in the terminal to run the application:

node index.js

Output: 

Explanation: 

  • In this example, we define a custom error-handling middleware function errorhandler that logs the error stack and sends a response with a status code of 500 and the message “Something went wrong!”.
  • We then use the custom error handling middleware by adding the app.use(errorhandler) after defining it.
  • This error-handling middleware will catch any errors thrown in the previous middleware or routes, and handle them according to the logic defined in the errorHandler function.
  • The first line App is listening on port 3000 is logged when the Express app starts listening on port 3000.
  • If you make a request to the app, the custom middleware will throw an error, which will then be caught by the error-handling middleware. The error stack trace will be logged to the console, and the response sent to the client will have a status code of 500 and the message “Something went wrong!”.

Example 2: Using the try-catch statement: You can use the try-catch statement to handle errors that occur within a specific block of code.

Javascript

const express = require('express');

const app = express();

app.get('/', (req, res, next) => {

    try {

        const data = someFunctionThatMightThrowError();

        res.status(200).json(

            { message: 'Data retrieved successfully', data });

    } catch (error) {

        next(error);

    }

});

app.use((err, req, res, next) => {

    console.error(err.stack);

    res.status(500).json(

        { message: 'Something went wrong!' });

});

app.listen(3000, () => {

    console.log('App is listening on port 3000');

});

Explanation:

  • In this example, we wrap the code that might throw an error in a try block. If an error is thrown, it will be caught by the corresponding catch block, which logs the error stack and sends a response with a status code of 500 and the message “Something went wrong!”.
  • This approach allows for more fine-grained error handling, as the try-catch statement can be used multiple times in different middleware functions or routes.

Steps to run the application: Write the below code in the terminal to run the application:

node index.js

Output:

Explanation:

  • If you make a request to the app, the custom middleware will throw an error, which will then be caught by the try-catch statement. The error stack trace will be logged to the console, and the response sent to the client will have a status code of 500 and the message “Something went wrong!”.
  • Note that the [ERROR STACK TRACE] part of the output will vary depending on the exact error that was thrown. It will contain details about the error, such as the error message and the location in the code where the error was thrown.
  • his output will be displayed if you make a request to the app and an error is thrown by the custom middleware. The error stack trace will be logged to the console and the response sent to the client will have a status code of 500 and the message “Something went wrong!”.
  • This output will be displayed when the Express app starts listening on port 3000. No error will be thrown if you do not make any requests to the app.

Example 3: Using the next() function: You can use the next() function to pass errors to the next middleware function in the chain.

Javascript

const express = require('express');

const app = express();

app.get('/', (req, res, next) => {

    const data = someFunctionThatMightThrowError();

    if (!data) {

        return next(new Error('Error retrieving data'));

    }

    res.status(200).json(

        { message: 'Data retrieved successfully', data });

});

app.use((err, req, res, next) => {

    console.error(err.stack);

    res.status(500).json(

        { message: 'Something went wrong!' });

});

app.listen(3000, () => {

    console.log('App is listening on port 3000');

});

Explanation: 

  • In this example, we have two middleware functions. The first middleware function throws an error, and the second middleware function is used for error handling. If an error is thrown in the first middleware function, the control flow is passed to the second middleware function using the next() function. The error is then logged to the console and a response with a status code of 500 and the message “Something went wrong!” is sent to the client.
  • This approach allows for error handling to be handled separately from the middleware functions that perform the core functionality of the application.

Steps to run the application: Write the below code in the terminal to run the application:

node index.js

Here’s an example using curl:

  • Open a terminal or command prompt.
  • Navigate to the directory where the program is located.
  • Start the application by running node app.js.
  • In another terminal window, run the following command to make a request to the ‘/’ endpoint:
curl http://localhost:3000

Output:

  • If you make a request to the app, the first middleware function will throw an error. The error will be passed to the second middleware function using the next() function, where it will be logged to the console and a response with a status code of 500 and the message “Something went wrong!” will be sent to the client.
  • Note that the [ERROR STACK TRACE] part of the output will vary depending on the exact error that was thrown. It will contain details about the error, such as the error message and the location in the code where the error was thrown.

Advantages of error handling used in express.js:

  1. Improved user experience: Error handling allows you to provide meaningful and user-friendly error messages to your users, rather than leaving them with a blank screen or a default error message. This improves the overall user experience and can help to prevent confusion or frustration.
  2. Better debugging: When errors occur in an application, it can be difficult to identify the cause without proper error handling. By capturing and logging errors, you can more easily debug your application and identify the root cause of any issues.
  3. Increased application stability: Error handling helps to prevent unhandled errors from crashing your application, which can lead to increased stability and fewer downtime incidents.
  4. Better maintainability: Error handling makes it easier to maintain your application by providing a clear and consistent way to handle errors. This can make it easier to identify and fix bugs, as well as to add new features.

Disadvantages of error handling used in express.js:

  1. Increased complexity: Error handling can add complexity to your application, as it requires you to anticipate and plan for potential errors. This can make your code more difficult to understand and maintain.
  2. Overhead: Error handling can add overhead to your application, as it requires additional logic and processing to capture and respond to errors. This can impact the performance of your application.
  3. False alarms: If error handling is not implemented correctly, it can lead to false alarms or unnecessary error messages being displayed to users. This can create confusion and damage user trust.
  4. Security risks: Improper error handling can create security risks, as it can reveal sensitive information or provide attackers with clues about potential vulnerabilities in your application.

Last Updated :
16 Feb, 2023

Like Article

Save Article

Search code, repositories, users, issues, pull requests…

Provide feedback

Saved searches

Use saved searches to filter your results more quickly

Sign up

Обработка ошибок¶

Функции промежуточного обработчика для обработки ошибок определяются так же, как и другие функции промежуточной обработки, но с указанием для функции обработки ошибок не трех, а четырех аргументов: (err, req, res, next). Например:

app.use(function (err, req, res, next) {
    console.error(err.stack);
    res.status(500).send('Something broke!');
});

Промежуточный обработчик для обработки ошибок должен быть определен последним, после указания всех app.use() и вызовов маршрутов; например:

var bodyParser = require('body-parser');
var methodOverride = require('method-override');

app.use(bodyParser());
app.use(methodOverride());
app.use(function (err, req, res, next) {
    // logic
});

Ответы, поступающие из функции промежуточной обработки, могут иметь любой формат, в зависимости от ваших предпочтений. Например, это может быть страница сообщения об ошибке HTML, простое сообщение или строка JSON.

В целях упорядочения (и для фреймворков более высокого уровня) можно определить несколько функций промежуточной обработки ошибок, точно так же, как это допускается для обычных функций промежуточной обработки. Например, для того чтобы определить обработчик ошибок для запросов, совершаемых с помощью XHR, и для остальных запросов, можно воспользоваться следующими командами:

var bodyParser = require('body-parser');
var methodOverride = require('method-override');

app.use(bodyParser());
app.use(methodOverride());
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);

В данном примере базовый код logErrors может записывать информацию о запросах и ошибках в stderr, например:

function logErrors(err, req, res, next) {
    console.error(err.stack);
    next(err);
}

Кроме того, в данном примере clientErrorHandler определен, как указано ниже; в таком случае ошибка явным образом передается далее следующему обработчику:

function clientErrorHandler(err, req, res, next) {
    if (req.xhr) {
        res.status(500).send({
            error: 'Something failed!',
        });
    } else {
        next(err);
    }
}

«Обобщающая» функция errorHandler может быть реализована так:

function errorHandler(err, req, res, next) {
    res.status(500);
    res.render('error', { error: err });
}

При передаче какого-либо объекта в функцию next() (кроме строки 'route'), Express интерпретирует текущий запрос как ошибку и пропустит все остальные функции маршрутизации и промежуточной обработки, не являющиеся функциями обработки ошибок. Для того чтобы обработать данную ошибку определенным образом, необходимо создать маршрут обработки ошибок, как описано в следующем разделе.

Если задан обработчик ошибок с несколькими функциями обратного вызова, можно воспользоваться параметром route, чтобы перейти к следующему обработчику маршрута. Например:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
app.get(
    '/a_route_behind_paywall',
    function checkIfPaidSubscriber(req, res, next) {
        if (!req.user.hasPaid) {
            // continue handling this request
            next('route');
        }
    },
    function getPaidContent(req, res, next) {
        PaidContent.find(function (err, doc) {
            if (err) return next(err);
            res.json(doc);
        });
    }
);

В данном примере обработчик getPaidContent будет пропущен, но выполнение всех остальных обработчиков в app для /a_route_behind_paywall будет продолжено.

Вызовы next() и next(err) указывают на завершение выполнения текущего обработчика и на его состояние. next(err) пропускает все остальные обработчики в цепочке, кроме заданных для обработки ошибок, как описано выше.

Стандартный обработчик ошибок¶

В Express предусмотрен встроенный обработчик ошибок, который обрабатывает любые возможные ошибки, встречающиеся в приложении. Этот стандартный обработчик ошибок добавляется в конец стека функций промежуточной обработки.

В случае передачи ошибки в next() без обработки с помощью обработчика ошибок, такая ошибка будет обработана встроенным обработчиком ошибок. Ошибка будет записана на клиенте с помощью трассировки стека. Трассировка стека не включена в рабочую среду.

Для запуска приложения в рабочем режиме необходимо задать для переменной среды NODE_ENV значение production.

При вызове next() с ошибкой после начала записи ответа (например, если ошибка обнаружена во время включения ответа в поток, направляемый клиенту), стандартный обработчик ошибок Express закрывает соединение и отклоняет запрос.

Поэтому при добавлении нестандартного обработчика ошибок вам потребуется делегирование в стандартные механизмы обработки ошибок в Express в случае, если заголовки уже были отправлены клиенту:

function errorHandler(err, req, res, next) {
    if (res.headersSent) {
        return next(err);
    }
    res.status(500);
    res.render('error', { error: err });
}

Понравилась статья? Поделить с друзьями:
  • Образец составления бухгалтерской справки при ошибке
  • Обработка ошибок python json
  • Обозначение ошибок на панели стиральной машины lg
  • Оборудование для чтения ошибок автомобиля
  • Обработка ошибок mysqli