1
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?

Cloudflare Workers + HonoJSチュートリアル④:レート制限(Rate Limiting)実装

Posted at

はじめに

本記事では前回までの認証付き Hono アプリに、Rate Limiting(レート制限)を導入する方法を紹介します。

レート制限をかけることで、短時間で大量のリクエストが飛んできた場合にエラーを返し、サービスの安定稼働を図れるようにします。

1. レート制限の概要

短時間であまりに多くのリクエストが発生すると、サーバーは負荷が高まり、他の正常なユーザーのリクエストに応答できなくなる恐れがあります。
そこで一定時間内に処理するリクエスト数を制限し、しきい値を超えた場合はエラーレスポンスを返却する仕組みを導入します。

2. 全体フローイメージ

3. インストール

Rate Limiting を実装するためのライブラリは複数ありますが、ここではシンプルに「メモリ上でリクエスト回数をカウントするだけ」の例を示します。
本番運用では分散環境に対応できるよう Redis などを使う場合が多いです。

4. ディレクトリ構成

my-hono-crud/
├─ .env
├─ package.json
├─ tsconfig.json
├─ src/
│   ├─ index.ts
│   ├─ routes/
│   │   └─ auth.ts
│   ├─ middlewares/
│       ├─ auth.ts
│       └─ rateLimit.ts   // 今回追加
│   └─ users/
│       └─ index.ts
└─ ...

5. レート制限ミドルウェアの実装例

5-1. src/middlewares/rateLimit.ts

import { Context, Next } from 'hono'

// IPごとの履歴を保持するためのマップ
const requestHistory = new Map<string, number[]>()

// 1分間に許容するリクエスト数
const LIMIT = 10
// しきい値時間 (ミリ秒)
const TIME_WINDOW = 60 * 1000

export const rateLimitMiddleware = async (c: Context, next: Next) => {
  // IPアドレス取得(プロキシ環境やCloudflare環境に対応)
  const ip = c.req.header('x-forwarded-for') || 
             c.req.header('CF-Connecting-IP') || 
             c.req.header('X-Real-IP') || 
             c.env?.remoteAddr ||  // Cloudflare Workers環境用
             'unknown'

  const now = Date.now()
  const timestamps = requestHistory.get(ip) || []

  // 古いタイムスタンプを除去
  const recentTimestamps = timestamps.filter((ts: number) => now - ts < TIME_WINDOW)

  // 今回のアクセスを追加
  recentTimestamps.push(now)
  requestHistory.set(ip, recentTimestamps)

  // LIMITを超えていれば429エラーを返却
  if (recentTimestamps.length > LIMIT) {
    return c.text('Too Many Requests', 429)
  }

  await next()
}

5-2. src/index.ts への組み込み

import { Hono } from 'hono'
import { loginHandler } from './routes/auth'
import { rateLimitMiddleware } from './middlewares/rateLimit'
import userApp from './users/index'
import 'dotenv/config'

const app = new Hono()

// レート制限ミドルウェアを全ルートで使用
app.use('*', rateLimitMiddleware)

// ログイン用エンドポイント
app.post('/login', loginHandler)

// ユーザー CRUD エンドポイント
app.route('/users', userApp)

export default app

6. 動作確認

# 連続で11回叩いてみる例
for i in {1..11}; do
  curl http://localhost:8787
done

7. まとめと応用

  • レート制限 は高負荷攻撃やスパムなどを防ぐうえで重要な施策です。
  • 本番環境では Redis などを利用して スケーラブル な運用を検討しましょう。
  • IP アドレス 以外にも ユーザーIDJWT トークン 単位でのレート制限も可能です。
1
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
1
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?