如何对Next.js Server Actions进行请求速率限制?
针对Next.js Server Actions的特定速率限制方案
方案1:在Server Action内部嵌入速率限制逻辑
直接在需要限制的Server Action函数开头添加针对性的速率限制检查,基于用户标识(如IP、用户ID)和Action名称区分不同操作,精准控制单Action的限流规则。
示例代码:
// 封装通用速率限制工具函数 async function rateLimit(actionKey: string, identifier: string, limit: number, windowMs: number) { // 可选用Redis、Vercel KV等持久化存储,开发环境也可临时用内存存储 const key = `rate-limit:${actionKey}:${identifier}`; const currentCount = await getRateLimitCount(key); if (currentCount >= limit) { throw new Error('请求过于频繁,请稍后再试'); } await incrementRateLimitCount(key, windowMs); } // 目标Server Action export async function submitFormAction(formData: FormData) { // 获取用户IP(App Router中通过headers()获取) const headers = headers(); const userIp = headers.get('x-forwarded-for') || headers.get('remote-address') || 'unknown'; // 对该Action设置限流:1分钟最多5次请求 await rateLimit('submit-form', userIp, 5, 60000); // 后续业务逻辑 // ... }
方案2:通过Middleware区分不同Server Action
利用Next.js Middleware拦截根路径的POST请求,通过Server Actions自带的__NEXT_ACTION字段识别具体操作,集中配置限流规则。
示例代码:
// middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export async function middleware(request: NextRequest) { // 仅处理Server Actions的根路径POST请求 if (request.method === 'POST' && request.nextUrl.pathname === '/') { const formData = await request.formData(); const actionId = formData.get('__NEXT_ACTION'); // 根据实际Action标识匹配(可通过浏览器网络请求查看__NEXT_ACTION的具体值) if (actionId?.includes('submitFormAction')) { const userIp = request.ip || request.headers.get('x-forwarded-for') || 'unknown'; const isRateLimited = await checkRateLimit('submit-form', userIp, 5, 60000); if (isRateLimited) { return NextResponse.json({ error: '请求过于频繁,请稍后再试' }, { status: 429 }); } } } return NextResponse.next(); }
方案3:为Server Actions配置自定义路由(Next.js 14+)
Next.js 14及以上版本支持给Server Actions指定独立路由,这样就能像常规API路由一样按路径配置速率限制。
在next.config.js中配置:
/** @type {import('next').NextConfig} */ const nextConfig = { experimental: { serverActions: { routes: { '/api/actions/submit-form': { action: './app/actions/submitFormAction.ts', }, '/api/actions/another-action': { action: './app/actions/anotherAction.ts', }, }, }, }, }; module.exports = nextConfig;
组件中调用时指定自定义路由:
<form action="/api/actions/submit-form"> {/* 表单内容 */} <button type="submit">提交</button> </form>
内容的提问来源于stack exchange,提问作者Qiong Wu
相关产品推荐
相关产品推荐

