ThinkPHP路由白名单必须配置在app/middleware.php中全局中间件里,而非route/app.php;需用$request->url(true)获取完整URL,以前缀匹配方式校验,放行时return $next($request),否则返回403。

ThinkPHP 路由白名单必须在 app/middleware.php 里配,不是路由文件
很多人在 route/app.php 里加判断逻辑,结果中间件根本没跑——因为路由匹配发生在中间件执行之后。白名单控制本质是「请求进来时就决定放不放行」,必须靠全局中间件拦截。
实操建议:
- 打开
app/middleware.php,把自定义中间件加到数组开头(越靠前越早执行) - 中间件里用
$request->url(true)获取带域名的完整路径,避免只截pathinfo导致协议/子目录下失效 - 白名单规则建议用前缀匹配(如
/api/v1/),别用正则硬刚,维护成本高还容易漏逃逸字符
中间件里怎么写白名单判断才不绕晕自己
核心逻辑就三步:取当前 URL → 对比白名单 → 放行或中断。别在中间件里查数据库或读配置文件,会拖慢所有请求。
常见错误现象:404 或 500 但日志没报错——其实是中间件里用了未定义的 $this->config 或忘了 return $next($request)。
立即学习“PHP免费学习笔记(深入)”;
实操建议:
- 白名单列表直接写死在中间件里(开发期),或从
config/route.php读(上线后),别动态拼接 - 用
str_starts_with()(PHP 8.0+)或strpos($url, $prefix) === 0判断,别用in_array()查完整 URL,性能差且不支持通配 - 放行条件要明确:仅当 URL 匹配白名单时
return $next($request);否则直接return json(['code'=>403, 'msg'=>'forbidden'])
为什么加了白名单,后台接口还是被拦了
最常见原因是 ThinkPHP 的「多应用模式」或「子域名部署」导致 $request->url() 返回的路径和你预期不一致。比如部署在 https://admin.example.com/api/user,但中间件拿到的是 /api/user,而你白名单写的是 https://admin.example.com/api/。
使用场景差异:
- 本地开发(
php think run):URL 是http://127.0.0.1:8000/api/xxx - Nginx 反向代理后:可能被 strip 掉
/admin前缀,实际进 PHP 的是/api/xxx - Apache + .htaccess:PATH_INFO 可能被重写污染
实操建议:
- 调试时第一件事:在中间件开头加
var_dump($request->url(true)); die;看真实值 - 如果部署有子路径(如
/myapp/),白名单前缀要同步加上,别只写/api/,得写/myapp/api/ - 确认
APP_DEBUG = true时是否关闭了中间件缓存(runtime/middleware.php有时不会自动更新)
TP6.1+ 的 allowCrossDomain 和白名单冲突吗
不冲突,但顺序很重要。跨域中间件(如 think-middleware-cors)一般放在白名单之后,否则未授权请求也会带上 Access-Control-Allow-Origin 头,违反安全原则。
性能影响很实际:每个请求都走一遍白名单判断,如果列表超过 20 条且用正则,QPS 会明显下跌。
实操建议:
- 把白名单中间件放在
middleware.php数组最前面,跨域、日志、鉴权等后续中间件排在它后面 - 白名单条目控制在 10–15 条以内,用层级前缀收敛(如
/api/涵盖全部接口,别单独列/api/user、/api/order) - 线上环境务必关掉
APP_DEBUG,否则中间件类每次都会重新扫描,白名单判断反而成性能瓶颈
真正难的不是写几行判断,而是每次换部署方式(Docker、Nginx location、CDN 回源)都要重新验证 $request->url() 的输出是否可靠。这点很容易被忽略,一上线就出问题。


















