应从think\Response类的redirect()静态方法开始读源码,它先调用Response::create()创建响应实例,再链式设置Location头和状态码(默认302),最终返回该实例;控制器中redirect()是全局函数,委托至此,而非门面think\facade\Redirect。

从哪里开始读 redirect() 的源码
直接定位到 thinkResponse 类的 redirect() 静态方法,它不是控制器里的快捷函数 —— 控制器里调用的 redirect() 是全局函数,最终会委托给 Response::redirect()。别在 thinkacadeRedirect 里绕圈子,那个只是门面,不包含核心逻辑。
redirect() 怎么构造响应对象
源码里关键行为是:先调用 Response::create() 创建一个空响应实例,再链式调用 ->header('Location', $url)->code($code) 设置头和状态码,最后返回该实例。注意两点:
-
$code默认是302,传301或307才会改写状态码,但不会自动处理缓存头(如Cache-Control) -
$url如果是相对路径(如'/login'),框架不会自动补全域名;如果是完整 URL(如'https://a.com/login'),则原样塞进Location头,$withPrefix参数会被忽略 - 真正触发跳转的是后续的
Response::send(),它检查是否已发送过头(headers_sent()),没发才输出Location并exit
为什么 redirect() 在 Swoole 下容易失效
根本原因是 Response::send() 依赖 headers_sent() 判断能否发头,但在 Swoole 常驻进程中,PHP 的 headers 缓冲机制可能被复用或污染。常见表现:
- 上一个请求残留了
Location头,当前请求没设但依然跳转 - 中间件提前调用了
echo或var_dump(),导致headers_sent()返回true,send()直接跳过而不报错 - 多个协程并发写同一 response 对象,
header()调用被覆盖或丢弃
所以生产环境用 Swoole 时,必须确保所有中间件、控制器、模板里没有意外输出,且 redirect 必须在响应体完全空闲时调用。
别被 jump() 和模板 success()/error() 带偏
jump() 在 TP6+ 中默认不注册,也不参与响应生命周期 —— 它只是个模板函数,底层仍靠 redirect() 实现。如果你在控制器里直接调 jump('success'),会抛 TemplateNotFoundException,因为框架根本没加载对应模板。
真正安全的跳转入口只有两个:redirect() 函数(推荐),或手动 new Response 并 setHeader。其他封装层(如 traitscontrollerJump)只适用于 TP5 旧项目迁移,新代码应避免。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











