2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Node.js] Expressのタイムアウト時間を設定した上で、408レスポンスを返す

Last updated at Posted at 2023-01-06

はじめに

↑自分が過去に書いた記事では、Expressでのタイムアウト時間設定を記載しました
しかし、この設定だけだとHTTPレスポンスが返らないので、ちゃんと相手がいるシステムだと困るなあと思い、レスポンスを返せるように実装してみました

curlやPostmanでtimeout設定だけしたExpressサーバのAPIを叩いてみた

% curl http://localhost:3000/time
curl: (52) Empty reply from server

image.png

レスポンスがクライアントに返っていないことがわかります
では、408ステータスが返却されるようにしてみましょう↓

実装

タイムアウトを設定し、408をレスポンスする関数を作成

timeoutSeetting.ts
import { Response } from 'express'

const TIMEOUT_MS = 1000 * 60 // 60sec

const setResponseTimeOut = (res: Response) => {
  res.setTimeout(TIMEOUT_MS, () => {
    // 408 Request Timeoutの定義に従いConnectionをcloseする
    res.setHeader('Connection', 'close')
    res.sendStatus(408)
  })
}

expressのルーティング定義から作成した関数を最初にコールしておく

app.ts
app.get('/time', async (req: Request, res: Response) => {
  setResponseTimeOut(res)

  // do something...

  // 既に408を返している場合はレスポンスしない
  if (!res.headersSent) res.sendStatus(200)
})

試してみる

めんどくさいので1ファイルにどかっと書きました

app.ts
// タイムアウト時間は1秒と設定
const TIMEOUT_MS = 1000
const setResponseTimeOut = (res: Response, next: NextFunction) => {
  res.setTimeout(TIMEOUT_MS, () => {
    // 408 Request Timeoutの定義に従いConnectionをcloseする
    res.setHeader('Connection', 'close')
    console.log(`${TIMEOUT_MS}ms経過 Timeoutレスポンスを返却します`)
    console.timeEnd('/time')
    res.sendStatus(408)
  })
}

app.get('/time', async (req: Request, res: Response, next: NextFunction) => {
  console.time('/time')
  setResponseTimeOut(res, next)
  // 3秒かかる処理
  await new Promise<void>((resolve) => {
    setTimeout(() => {
      resolve()
    }, 3000)
  })
  await new Promise<void>((resolve) => {
    setTimeout(() => {
      console.log('408を返した後も処理は続くので注意!')
      resolve()
    }, 1000)
  })
  if (!res.headersSent) res.sendStatus(200)
})
// サーバリッスンなど省略

APIを叩くと...

1000ms経過 Timeoutレスポンスを返却します
/time: 1.003s
408を返した後も処理は続くので注意!

設定したタイムアウト時間である1秒経過後に408がレスポンスされています

image.png

注意点

ターミナルにも出力していますが、408が返った後も処理自体は継続して動いているので注意が必要です
408を受け取ったクライアント側が500エラーなんかと同じように扱って、リトライをしまくると、冪等性のないAPIだった場合データのダブりがたくさん出ます

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?