ThinkPHP API中间件必须显式绑定到路由或分组才执行,推荐使用Route::group()在route/app.php中为/api/*路径统一绑定如jwt.auth等中间件,并支持except排除特定接口;域名路由需用Route::domain()包裹并绑定中间件,全局注册仅适用于全站通用逻辑。

ThinkPHP API 应用中间件不能靠“默认启用”或“自动扫描”,必须显式绑定到具体作用域,否则根本不会执行。
路由级绑定是 API 场景最可控的方式
全局注册的中间件(app/middleware.php)会拦截所有请求,包括静态资源、预检请求(OPTIONS)、健康检查等,容易误伤;而路由级绑定能精准覆盖 /api/* 路径,避免干扰非 API 流程。
- 在
route/app.php中用Route::group()统一包裹 API 路由,并链式调用->middleware('jwt.auth') - 不要写成
Route::group('api', [...] )->middleware(...)后再单独定义Route::get('api/login', ...)——后者脱离分组,中间件不生效 - 若需排除登录、刷新 token 等接口,用
->except(['login', 'refresh']),注意这里匹配的是路由名(如api/login)或完整路径(如/api/login),不是控制器方法名 - 多个中间件按顺序执行:
->middleware(['cors', 'jwt.auth', 'rate_limit']),数组索引即执行优先级
域名路由下必须用 Route::domain() 包裹再绑中间件
如果你的 API 部署在独立域名(如 api.example.com),中间件不能靠路径前缀推断,必须让框架明确知道“这个中间件只属于这个域名”。
- 错误写法:
Route::group('api', ...)->middleware('jwt.auth')—— 它仍匹配所有域名下的/api/路径 - 正确写法:
Route::domain('api.example.com', function () { Route::group('v1', [...]); })->middleware('jwt.auth') - 多个域名共用一套逻辑?传数组:
Route::domain(['api.example.com', 'staging.api.example.com'], function () { ... }) - Web 服务器(Nginx/Apache)必须把所有这些域名的请求都指向同一
public/index.php,否则框架根本收不到请求,中间件无从谈起
app/middleware.php 里的全局注册只适合真正全站通用逻辑
比如统一 JSON 响应封装(UniformJsonResponse)、异常兜底、日志埋点这类“不管什么请求都要走一遍”的逻辑。但 JWT 验证、权限校验、跨域头设置等 API 特有行为,放这里大概率会卡住登录页、H5 页面甚至 favicon.ico 请求。
- 全局中间件数组中,
think\middleware\Lang和think\middleware\SessionInit这类基础中间件可保留,但jwt.auth这类业务中间件建议移出 - 如果硬要全局注册,务必加白名单判断:
if (stripos($request->url(), '/api/') !== 0) return $next($request); - 注意中间件执行顺序:全局中间件数组索引越小越早执行,
UniformJsonResponse必须放在缓存中间件之后、响应发送之前,否则可能被缓存截断
最容易被忽略的一点:中间件类本身是否真被调用,和它有没有被“注册”无关,只取决于有没有被“绑定到某条路由或某个分组”。哪怕你把 20 个中间件都写进 app/middleware.php,只要没在路由定义里显式挂上 ->middleware('xxx'),它就永远不会运行一次。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











