summaryrefslogtreecommitdiff
path: root/lib/rate-limit.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rate-limit.ts')
-rw-r--r--lib/rate-limit.ts63
1 files changed, 63 insertions, 0 deletions
diff --git a/lib/rate-limit.ts b/lib/rate-limit.ts
new file mode 100644
index 00000000..db90dcff
--- /dev/null
+++ b/lib/rate-limit.ts
@@ -0,0 +1,63 @@
+// lib/rate-limit.ts
+import { NextRequest } from 'next/server';
+import { getClientIp } from './network/get-client-ip';
+
+interface RateLimitResult {
+ success: boolean;
+ remaining?: number;
+}
+
+// 메모리 기반 간단한 rate limiter (프로덕션에서는 Redis 사용 권장)
+const requestCounts = new Map<string, { count: number; resetTime: number }>();
+
+
+
+export default async function rateLimit(
+ request: NextRequest,
+ maxRequests: number = 100,
+ windowMs: number = 60 * 60 * 1000 // 1시간
+): Promise<RateLimitResult> {
+ // 클라이언트 IP 가져오기
+ const clientIP = getClientIp(request);
+
+
+ const now = Date.now();
+ const key = `rate_limit:${clientIP}`;
+
+ // 기존 요청 정보 가져오기
+ let requestInfo = requestCounts.get(key);
+
+ // 윈도우가 리셋된 경우 또는 첫 요청인 경우
+ if (!requestInfo || now > requestInfo.resetTime) {
+ requestInfo = {
+ count: 1,
+ resetTime: now + windowMs
+ };
+ requestCounts.set(key, requestInfo);
+ return { success: true, remaining: maxRequests - 1 };
+ }
+
+ // 요청 한도 초과 확인
+ if (requestInfo.count >= maxRequests) {
+ return { success: false, remaining: 0 };
+ }
+
+ // 요청 카운트 증가
+ requestInfo.count++;
+ requestCounts.set(key, requestInfo);
+
+ return {
+ success: true,
+ remaining: maxRequests - requestInfo.count
+ };
+}
+
+// 주기적으로 만료된 항목 정리 (메모리 누수 방지)
+setInterval(() => {
+ const now = Date.now();
+ for (const [key, value] of requestCounts.entries()) {
+ if (now > value.resetTime) {
+ requestCounts.delete(key);
+ }
+ }
+}, 60 * 60 * 1000); // 1시간마다 정리 \ No newline at end of file