LaravelAPI如何做接口限流_LaravelAPI自定义限流策略【操作】

2次阅读

laravel API 路由中 throttle 中间件不生效,因默认依赖 session 而 API 路由关闭了 StartSession;应自定义 ThrottleRequests 的 resolveRequestSignature() 方法,优先用 bearerToken()、fallback 到 IP,并重写 buildResponse() 返回 json 格式 429 响应及 Retry-After 头。

LaravelAPI如何做接口限流_LaravelAPI自定义限流策略【操作】

为什么 Laravel 的 throttle 中间件在 API 路由里不生效

因为默认的 throttle 中间件依赖 session,而 API 路由通常关闭了 session 启动(api 中间件组默认不含 StartSession)。没 session,Laravel 就没法按用户维度识别请求来源,限流直接退化成“每秒最多 X 次”,且无法区分不同客户端。

  • 检查你的路由是否在 routes/api.php 里,并被 api 中间件组包裹 —— 这是问题高发场景
  • 不要手动加 StartSession 到 API 路由:API 应无状态,加 session 会破坏无状态性,还可能引发跨域或并发问题
  • 正确做法是改用基于请求标识(如 IP、token、header)的限流策略,跳过 session 依赖

如何用 ThrottleRequests 自定义 key 实现 API 限流

Laravel 的 ThrottleRequests 中间件支持重写 resolveRequestSignature() 方法来定义限流 key。API 场景下,最常用的是从 Authorization header 提取 token(对应用户),或 fallback 到 IP。

  • app/http/Middleware/ApiThrottleRequests.php继承 ThrottleRequests
  • 重写 resolveRequestSignature():优先取 $request->bearerToken(),为空则用 $request->ip()
  • 注意:Bearer Token 若来自第三方 OAuth(如 Passport),需确保已解码并验证有效性;否则攻击者可伪造 token 绕过限流
  • 示例 key 返回值:return $request->bearerToken() ?: $request->ip();

throttle:60,1,by=ip 这种写法在 API 里为什么危险

它强制按 IP 限流,看似简单,但实际在 NAT 环境(公司网络、校园网、移动运营商出口)下,几十甚至上百用户共享同一个公网 IP,极易误伤正常用户。

  • 别在面向用户的 API 接口上直接用 by=ip,尤其登录、注册、短信验证码等高频敏感接口
  • 如果必须用 IP 作为兜底(比如未带 token 的访客请求),应单独路由分组,并设置更宽松阈值(如 throttle:10,1
  • redis 后端下,IP 限流 key 是 throttle:ip:xxx.xxx.xxx.xxx,可通过 redis-cli keys "throttle:ip:*" 快速确认是否积异常

自定义限流响应格式与状态码怎么统一处理

Laravel 默认返回 HTML 页面(含 429 状态),但 API 客户端只认 JSON 和标准状态码。不处理会导致前端解析失败或重试逻辑混乱。

  • 在自定义中间件中覆盖 buildResponse() 方法,返回 response()->json() 并设 status(429)
  • 务必带上 Retry-After 响应头(单位:秒),这是 HTTP/1.1 标准字段,多数 SDK 会自动等待后重试
  • 示例返回体:{"message":"Too many requests.","retry_after":60} —— 不要加多余字段,避免客户端解析歧义
  • 别在控制器里 try/catch 429:限流是前置拦截,应在中间件层就完成响应构造

Laravel 的限流不是开箱即用的开关,关键在「谁来限」和「怎么响应」——前者决定是否精准,后者决定是否可用。漏掉 bearerToken fallback、忽略 Retry-After 头、或把 IP 限流用在用户主路径上,都是上线后才暴露的坑。

text=ZqhQzanResources