6
4

More than 3 years have passed since last update.

ExpressのAsync Errorのハンドリング

Posted at

問題点: asyncでリクエストハンドラを定義して処理中に例外が発生してもハンドリングできない

たとえば、http://localhost:3333/notfoundrouteのように存在しないルートにアクセスしたら、ステータスコード:404、ボディコンテンツにRoute not foundを返したい場合において、以下のコードを実装したとする。

import express, { Request, Response, NextFunction } from "express";

const app = express();

app.get("/hi", (req, res) => {
  res.send("Say hi");
});

// 問題の箇所
// ここで例外を発生させる
app.get("*", async (req, res) => {
  throw new Error("Route not found");
});

// エラーを扱うためのハンドラ
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  return res.status(404).send(err.message);
});

app.listen(3333, () => console.log("Listenin on port 3333"));

しかし、実行結果としては、レスポンスが返ってこない

curl -v localhost:3333/notfoundroute
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3333 (#0)
> GET /notfoundroute HTTP/1.1
> Host: localhost:3333
> User-Agent: curl/7.64.1
> Accept: */*
>

サーバ側のログ出力も以下のようになっていて、Promiseを上手く扱えていない。

(node:11743) UnhandledPromiseRejectionWarning: Error: Route not found
...
(node:11743) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:11743) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

解決策1: nextで例外をラップする。

問題の箇所を以下のように変更する。

...

app.get("*", async (req, res, next) => {
  next(new Error("Route not found"));
});

...

実行結果は、期待した結果が得られている。

curl -v localhost:3333/notfoundroute
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3333 (#0)
> GET /notfoundroute HTTP/1.1
> Host: localhost:3333
> User-Agent: curl/7.64.1
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< X-Powered-By: Express
< Content-Type: text/html; charset=utf-8
< Content-Length: 15
< ETag: W/"f-f4JcZAomq7bAiiL2cdorz+qCRSw"
< Date: Tue, 05 May 2020 07:00:15 GMT
< Connection: keep-alive
< 
* Connection #0 to host localhost left intact
Route not found* Closing connection 0

解決策2: express-async-errorsパッケージをインポートする。

必要なパッケージをインストールする。

yarn add express-async-errors

問題の箇所は変更しなくてもよいが、express-async-errorsをインポートする。

import express, { Request, Response, NextFunction } from "express";
import "express-async-errors";
...

app.get("*", async (req, res) => {
  throw new Error("Route not found");
});

...

こちらも実行結果は、期待した結果が得られている。

curl -v localhost:3333/notfoundroute
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3333 (#0)
> GET /notfoundroute HTTP/1.1
> Host: localhost:3333
> User-Agent: curl/7.64.1
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< X-Powered-By: Express
< Content-Type: text/html; charset=utf-8
< Content-Length: 15
< ETag: W/"f-f4JcZAomq7bAiiL2cdorz+qCRSw"
< Date: Tue, 05 May 2020 07:00:15 GMT
< Connection: keep-alive
< 
* Connection #0 to host localhost left intact
Route not found* Closing connection 0
6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4