You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

35 lines
1.1 KiB

import { fail } from "@/lib/response";
import { checkIpRateLimit } from "@/modules/cache/ip-rate-limiter";
import { checkRateLimit } from "@/modules/cache/rate-limiter";
import type { NextResponse } from "next/server";
function extractClientIp(request: Request): string {
const forwarded = request.headers.get("x-forwarded-for");
if (forwarded) {
return forwarded.split(",")[0]?.trim() || "unknown";
}
return request.headers.get("x-real-ip") ?? "unknown";
}
/** 客户 + IP 双限流,超限返回 429 响应 */
export async function enforceRateLimits(
request: Request,
customerId: string,
): Promise<NextResponse | null> {
const ip = extractClientIp(request);
const ipResult = await checkIpRateLimit(ip);
if (!ipResult.allowed) {
const message = ipResult.banned
? "IP 已被临时封禁,请稍后再试"
: "请求过于频繁,请稍后再试";
return fail("RATE_LIMITED", message, 429);
}
const customerResult = await checkRateLimit(customerId);
if (!customerResult.allowed) {
return fail("RATE_LIMITED", "请求过于频繁,请稍后再试", 429);
}
return null;
}