重定向应使用 redirect(),而非 url() 或 buildUrl();转发应使用 action() 或 invoke();Route::redirect() 仅用于静态路由映射,不支持动态逻辑;session 丢失多因域名或协议配置不当。

重定向用 redirect(),不是 url() 或 buildUrl()
很多人写完路由规则后想跳转,下意识调用 url() 生成链接再手动 header('Location: ...'),这既绕路又容易漏掉状态码、跨域或 HTTPS 适配。ThinkPHP 原生的 redirect() 才是正确入口,它自动处理协议、域名、端口和基础路径(APP_SUB_DOMAIN_DEPLOY 或 URL_HTML_SUFFIX 开启时也兼容)。
常见错误现象:redirect('admin/index') 在子目录部署时跳到根目录,或 HTTPS 站点跳成 HTTP —— 这是因为没传完整路由名,或没配置 url_domain_deploy 和 url_convert。
- 用绝对路由名(如
'admin/index'),别用相对路径('../index') - 带参数重定向:
redirect('user/profile', ['id' => 123, 'tab' => 'info']),参数会自动拼成 query 或按路由变量注入 - 指定状态码:
redirect('login', [], 302),生产环境慎用 301(缓存难清除) - 跨模块跳转必须写全:
redirect('api/v1/users'),不能省略api模块名
转发用 think\facade\Hook::listen()?错,该用 invoke() 或 action()
转发(forward)是服务端内部行为,不改变浏览器 URL,常用于权限校验后透传请求、或统一入口分发。但 ThinkPHP 没有叫 forward() 的函数,直接调 action() 最稳妥,invoke() 更底层但需手动构造 Request 对象。
容易踩的坑:有人在中间件里用 redirect() 伪装转发,结果浏览器地址栏变了,且 POST 数据丢失;还有人试图用 Hook::listen('action_begin') 拦截后改控制器 —— 这属于 hack 行为,不稳定,且无法复用原有中间件逻辑。
立即学习“PHP免费学习笔记(深入)”;
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 简单转发:
return action('User/read', ['id' => $id]);,会执行目标方法并返回其响应 - 需要共享当前 Request/Response 实例时,用
app()->invoke(\app\controller\User::class, 'read', ['id' => $id]) - 转发不继承原路由的
middleware配置,如果目标控制器需要鉴权,得自己补AuthMiddleware调用 - 避免循环转发:A → B → A,
action()不做栈检测,出错就是 PHP Fatal error: Maximum function nesting level
Route::redirect() 是静态路由映射,不是运行时跳转
这个方法常被误解为“给某个 URL 配个跳转”,但它只在路由注册阶段生效,生成的是一个永久重定向响应(默认 301),且不经过控制器生命周期 —— 中间件、过滤器、初始化逻辑全被跳过。适合做老链接归档、SEO 迁移,不适合动态判断后跳转。
典型误用场景:在 route/app.php 里写 Route::redirect('v1/user/:id', 'v2/user/:id', 302),以为能动态替换 ID,结果发现 :id 不解析,跳过去还是字面量。
- 路径支持通配符但仅限静态匹配:
Route::redirect('old-api/*', 'new-api/$1', 302),$1是捕获组,不是变量插值 - 不支持闭包或条件判断,所有逻辑必须提前写死
- 若需动态跳转(比如根据用户角色跳不同首页),必须在控制器或中间件里用
redirect() - 注意缓存:301 会被浏览器强缓存,调试阶段优先用 302
重定向后 session 丢失?检查 session.auto_start 和域名配置
最隐蔽的问题不是代码写错,而是部署环境导致 session 无法携带。ThinkPHP 默认用 PHP 内置 session,一旦重定向跨子域名(如 admin.example.com → www.example.com)或协议不一致(HTTP → HTTPS),cookie 就不会发送,Session::get() 返回空。
不是框架 Bug,是浏览器同源策略限制。本地开发时一切正常,上线就丢数据,八成是这里卡住。
- 确认
session.domain配置是否包含主域名前的点,例如.example.com(注意开头的点) - 检查
session.secure是否与当前协议匹配:HTTPS 站点必须设为true,否则 cookie 不带 Secure 标志,浏览器拒绝发送 - 避免在重定向前调用
Session::destroy()或clear(),有些同学为了“清旧态”误删了刚写入的登录态 - 调试技巧:重定向前 dump
session_id()和$_COOKIE[session_name()],对比跳转后是否一致
Route::redirect() 的静态本质 —— 它们不报错,但会让逻辑在特定环境静默失效。


















