エラー処理
Error Handlingは、 が同期と非同期の両方で発生するエラーをExpress がキャッチして処理する方法を指します。 Error Handlingは、 が同期と非同期の両方で発生するエラーをExpress がキャッチして処理する方法を指します。 Expressにはデフォルトのエラー ハンドラが付属しているので、始めるために自分で書く必要はありません。
キャッチエラー
Express がルートハンドラと ミドルウェアの実行中に発生するすべてのエラーをキャッチすることが重要です。
Errors in synchronous code
ルートハンドラとミドルウェア 内の同期コードで発生するエラーは追加の作業を必要としません。 同期コードがエラーをスローする場合、Expressは キャッチして処理します。 例: 同期コードがエラーをスローする場合、Expressは キャッチして処理します。例:
app.get('/', (req, res) => { throw new Error('BROKEN'); // Express will catch this on its own.});import { type Request, type Response } from 'express';
app.get('/', (req: Request, res: Response) => { throw new Error('BROKEN'); // Express will catch this on its own.});Errors in asynchronous code
The recommended way to write asynchronous handlers is with async functions.
Route handlers and middleware that return a Promise call next(value)
automatically when they reject or throw an error, and async functions always
return a Promise, so their errors reach Express with no extra work. 例:
app.get('/user/:id', async (req, res) => { const user = await getUserById(req.params.id); res.send(user);});import { type Request, type Response } from 'express';
app.get('/user/:id', async (req: Request, res: Response) => { const user = await getUserById(req.params.id); res.send(user);});If getUserById throws an error or rejects, next will be called with either
the thrown error or the rejected value. 拒否された値が指定されていない場合、 next
はExpress ルータが提供するデフォルトの Error オブジェクトで呼び出されます。
next()関数に何かを渡した場合('route'を除く)。
Expressは現在のリクエストをエラーとみなし、
残っている非エラー処理ルーティングとミドルウェア関数をスキップします。
Working with promise chains
If you build a promise chain instead of using an async function, return the
promise from the handler and Express will likewise call next automatically
when it rejects:
app.get('/', (req, res) => { return Promise.resolve().then(() => { throw new Error('BROKEN'); // Express will catch this and call next. });});import { type Request, type Response } from 'express';
app.get('/', (req: Request, res: Response) => { return Promise.resolve().then(() => { throw new Error('BROKEN'); // Express will catch this and call next. });});If the promise is not returned, Express does not know it exists, and you must
route the error yourself by providing next as the final catch handler.
Without it, the rejection would be unhandled and crash the process:
app.get('/', (req, res, next) => { Promise.resolve() .then(() => { throw new Error('BROKEN'); }) .catch(next); // Errors will be passed to Express.});import { type Request, type Response, type NextFunction } from 'express';
app.get('/', (req: Request, res: Response, next: NextFunction) => { Promise.resolve() .then(() => { throw new Error('BROKEN'); }) .catch(next); // Errors will be passed to Express.});This works because if a callback in the promise chain throws, the chain turns that exception into a rejection, which travels down to the final .catch. There, .catch calls its handler with the error as the first argument, which is exactly the argument next expects, so the error reaches Express.
Working with callback APIs
Errors produced by callback-based APIs, such as those in node:fs, are not
thrown and are not part of any promise. The callback receives them as its first
argument, and you must pass them to the next() function yourself, where
Express will catch and process them. 例:
app.get('/', (req, res, next) => { fs.readFile('/file-does-not-exist', (err, data) => { if (err) { next(err); // Pass errors to Express. } else { res.send(data); } });});import { type Request, type Response, type NextFunction } from 'express';
app.get('/', (req: Request, res: Response, next: NextFunction) => { fs.readFile('/file-does-not-exist', (err, data) => { if (err) { next(err); // Pass errors to Express. } else { res.send(data); } });});シーケンス内のコールバックがデータを提供しない場合、エラーのみを提供する場合は、次のように このコードを簡素化できます:
app.get('/', [ function (req, res, next) { fs.writeFile('/inaccessible-path', 'data', next); }, function (req, res) { res.send('OK'); },]);import { type Request, type Response, type NextFunction } from 'express';
app.get('/', [ function (req: Request, res: Response, next: NextFunction) { fs.writeFile('/inaccessible-path', 'data', next); }, function (req: Request, res: Response) { res.send('OK'); },]);In the above example, next is provided as the callback for fs.writeFile,
which is called with or without errors. エラーがなければ、2番目の
ハンドラが実行されます。そうでなければ、Expressはエラーをキャッチして処理します。
また、非同期コードを些細なものに減らすことで、同期エラー のキャッチに依存するハンドラのチェーンを使用することもできます。 例: 例:
app.get('/', [ function (req, res, next) { fs.readFile('/maybe-valid-file', 'utf-8', (err, data) => { res.locals.data = data; next(err); }); }, function (req, res) { res.locals.data = res.locals.data.split(',')[1]; res.send(res.locals.data); },]);import { type Request, type Response, type NextFunction } from 'express';
app.get('/', [ function (req: Request, res: Response, next: NextFunction) { fs.readFile('/maybe-valid-file', 'utf-8', (err, data) => { res.locals.data = data; next(err); }); }, function (req: Request, res: Response) { res.locals.data = res.locals.data.split(',')[1]; res.send(res.locals.data); },]);The above example contains a couple of trivial statements following the readFile
call. 上の例では、readFile
呼び出しからいくつかの些細な文があります。 readFile でエラーが発生した場合、エラーは Express に渡されます。 それ以外の場合は、
チェーン内の次のハンドラ
で同期エラー処理の世界にすばやく戻ります。 そして、上記の例はデータを処理しようとします。 これが失敗した場合、
同期エラーハンドラはそれをキャッチします。 readFileコールバックの
内でこの処理を行った場合、アプリケーションが終了する可能性があり、Expressエラー
ハンドラは実行されません。 Then, the example above tries to process the data. If this fails, then the
synchronous error handler will catch it. If you had done this processing inside
the readFile callback, then the application might exit and the Express error
handlers would not run.
Finally, for asynchronous code that provides no error-first callback, such as a timer, catch errors inside the asynchronous code itself and pass them to Express:
app.get('/', (req, res, next) => { setTimeout(() => { try { throw new Error('BROKEN'); } catch (err) { next(err); } }, 100);});import { type Request, type Response, type NextFunction } from 'express';
app.get('/', (req: Request, res: Response, next: NextFunction) => { setTimeout(() => { try { throw new Error('BROKEN'); } catch (err) { next(err); } }, 100);});The above example uses a try...catch block to catch errors in the
asynchronous code and pass them to Express. 上の例では、
非同期コードのエラーをキャッチし、Expressに渡すためにtry...catchブロックを使用しています。 try...catch
ブロックが省略された場合、Expressは同期
ハンドラコードの一部ではないため、エラーをキャッチしません。
どちらの方法を使っても、Expressエラーハンドラを呼び出し、 アプリケーションを存続させたい場合は Express がエラーを受け取ることを確認する必要があります。
デフォルトのエラーハンドラです
Expressには、アプリで発生する可能性のあるエラーを処理する内蔵のエラーハンドラが付属しています。 このデフォルトのエラー処理ミドルウェア関数は、ミドルウェア関数スタックの末尾に追加されます。 This default error-handling middleware function is added at the end of the middleware function stack.
If you pass an error to next() and you do not handle it in a custom error
handler, it will be handled by the built-in error handler; the error will be
written to the client with the stack trace. スタックトレースは本番環境に
含まれていません。
プロダクションモードでアプリを実行するには、環境変数 NODE_ENV を production に設定します。
エラーが書き込まれると、次の情報が 応答に追加されます:
- The
res.statusCodeis set fromerr.status(orerr.statusCode). If this value is outside the 4xx or 5xx range, it will be set to 500. res.statusMessageはステータスコードに従って設定されます。- 本文は、プロダクション
環境ではステータスコードメッセージのHTMLになります。そうでなければ、
err.stackになります。 err.headersオブジェクトで指定されたヘッダー。
If you call next() with an error after you have started writing the
response (for example, if you encounter an error while streaming the
response to the client), the Express default error handler closes the
connection and fails the request.
So when you add a custom error handler, you must delegate to the default Express error handler, when the headers have already been sent to the client:
function errorHandler(err, req, res, next) { if (res.headersSent) { return next(err); } res.status(500); res.render('error', { error: err });}import { type Request, type Response, type NextFunction } from 'express';
function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) { if (res.headersSent) { return next(err); } res.status(500); res.render('error', { error: err });}デフォルトのエラーハンドラは、コード内でエラー
を複数回呼び出してnext()を呼び出すとトリガされることに注意してください。 カスタムエラー処理ミドルウェアが導入されたとしてもです
Other error handling middleware can be found at Express middleware.
エラーハンドラの書き込み
Define error-handling middleware functions in the same way as other middleware functions,
except error-handling functions have four arguments instead of three:
(err, req, res, next). 例:
app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('Something broke!');});import { type Request, type Response, type NextFunction } from 'express';
app.use((err: Error, req: Request, res: Response, next: NextFunction) => { console.error(err.stack); res.status(500).send('Something broke!');});エラー処理ミドルウェアは、他の app.use()とルート呼び出しの後に最後に定義します。例:
const bodyParser = require('body-parser');const methodOverride = require('method-override');
app.use( bodyParser.urlencoded({ extended: true, }));app.use(bodyParser.json());app.use(methodOverride());app.use((err, req, res, next) => { // logic});import bodyParser from 'body-parser';import methodOverride from 'method-override';
app.use( bodyParser.urlencoded({ extended: true, }));app.use(bodyParser.json());app.use(methodOverride());app.use((err, req, res, next) => { // logic});import { type Request, type Response, type NextFunction } from 'express';import bodyParser from 'body-parser';import methodOverride from 'method-override';
app.use( bodyParser.urlencoded({ extended: true, }));app.use(bodyParser.json());app.use(methodOverride());app.use((err: Error, req: Request, res: Response, next: NextFunction) => { // logic});ミドルウェア関数内からのレスポンスは、HTMLエラーページ、シンプルなメッセージ、JSON文字列など、あらゆる形式で使用できます。
For organizational (and higher-level framework) purposes, you can define
several error-handling middleware functions, much as you would with
regular middleware functions. 例えば、XHRとそれ以外のリクエストに対してエラーハンドラ
を定義するには、次のようにします。
const bodyParser = require('body-parser');const methodOverride = require('method-override');
app.use( bodyParser.urlencoded({ extended: true, }));app.use(bodyParser.json());app.use(methodOverride());app.use(logErrors);app.use(clientErrorHandler);app.use(errorHandler);import bodyParser from 'body-parser';import methodOverride from 'method-override';
app.use( bodyParser.urlencoded({ extended: true, }));app.use(bodyParser.json());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);}import { type Request, type Response, type NextFunction } from 'express';
function logErrors(err: Error, req: Request, res: Response, next: NextFunction) { console.error(err.stack); next(err);}この例でも、clientErrorHandlerは以下のように定義されています。この場合、エラーは明示的に次のエラーに渡されます。
Notice that when you do not call next in an error-handling function, you are responsible for writing (and ending) the response. Otherwise, those requests will “hang” and will not be eligible for garbage collection.
function clientErrorHandler(err, req, res, next) { if (req.xhr) { res.status(500).send({ error: 'Something failed!' }); } else { next(err); }}import { type Request, type Response, type NextFunction } from 'express';
function clientErrorHandler(err: Error, req: Request, res: Response, next: NextFunction) { if (req.xhr) { res.status(500).send({ error: 'Something failed!' }); } else { next(err); }}“catch-all” errorHandler 関数を以下のように実装します(例えば:
function errorHandler(err, req, res, next) { res.status(500); res.render('error', { error: err });}import { type Request, type Response, type NextFunction } from 'express';
function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) { res.status(500); res.render('error', { error: err });}複数のコールバック関数を持つルートハンドラがある場合は、route パラメータを使用して次のルートハンドラにスキップできます。 例: 例:
app.get( '/a_route_behind_paywall', (req, res, next) => { if (!req.user.hasPaid) { // continue handling this request next('route'); } else { next(); } }, (req, res, next) => { PaidContent.find((err, doc) => { if (err) return next(err); res.json(doc); }); });import { type Request, type Response, type NextFunction } from 'express';
app.get( '/a_route_behind_paywall', (req: Request, res: Response, next: NextFunction) => { if (!req.user.hasPaid) { // continue handling this request next('route'); } else { next(); } }, (req: Request, res: Response, next: NextFunction) => { PaidContent.find((err, doc) => { if (err) return next(err); res.json(doc); }); });この例では、 getPaidContent ハンドラはスキップされますが、 /a_route_background_paywall の app に残っているハンドラは引き続き実行されます。
next()とnext(err)への呼び出しは、現在のハンドラが完了している状態を示します。
next(err)は、上記のように
に設定されているものを除いて、チェーン内の残りのハンドラをすべてスキップします。
next(err) will skip all remaining handlers in the chain except for those that are set up to
handle errors as described above.