使用技術など

  • Hono.jsを使用してapiのrate limitの実施を使用して見ます。
  • RedisはUpstashを使用しています。
  • Hono.jsを使用したウェブサーバーは今回はdeno(ver 2.1.4)にて走っています。

rate limit code

import { Redis } from "https://esm.sh/@upstash/redis";
import type { MiddlewareHandler } from "hono";

export const rateLimit = (
  requests: number = 100,
  window: number = 60
): MiddlewareHandler => {
  const redis = new Redis({
    url: Deno.env.get("UPSTASH_REDIS_REST_URL") ?? "",
    token: Deno.env.get("UPSTASH_REDIS_REST_TOKEN") ?? "",
  });

  return async (c, next) => {
    try {
      const ip = c.req.header("x-forwarded-for") || "unknown";
      const key = `rate-limit:${ip}`;

      if (
        !Deno.env.get("UPSTASH_REDIS_REST_URL") ||
        !Deno.env.get("UPSTASH_REDIS_REST_TOKEN")
      ) {
        console.warn("Redis credentials not configured, skipping rate limit");
        return next();
      }

      const current = await redis.incr(key);
      if (current === 1) {
        await redis.expire(key, window);
      }

      if (current > requests) {
        console.log(`Rate limit exceeded: ${c.req.method} ${c.req.path} 429`);
        return c.json(
          {
            error: "Too Many Requests",
            message: `Rate limit exceeded. Try again in ${window} seconds`,
          },
          429
        );
      }
      return next();
    } catch (error) {
      console.error("Rate limit error:", error);
      return next();
    }
  };
};
  • 主に、IPアドレスにより制限しリクエスト数と時間のタイムフレームは変更可能です。

こちらを以下のように使用できます。

import { Hono } from "hono";
import { rateLimit } from "./ratelimit.ts";
const app = new Hono();

app.use("*", rateLimit(100, 60));

また.envからの値がなぜか取れていなくてにものすごい時間がかかりました。プログラムを走らせるコマンドに -env-file=.env のフラッグを忘れずに。–allow-envだけではだめみたいだったので注意してください。

例)

コマンド

deno run --allow-env --allow-net --allow-read --allow-sys --env-file=.env index.ts