Hyperf控制器跳转需用response->redirect()返回302/303响应,不可用header()或render模板;它协程安全、可测试、符合PSR-7规范,且必须在响应体写入前调用。

Hyperf 是纯后端 HTTP 服务框架,控制器本身不直接“跳转页面”——它不操作浏览器,也不渲染 HTML 页面。所谓“跳转”,实际是返回一个 302 或 303 响应,让浏览器自己发起新请求。你真正要做的,是让控制器返回正确的响应对象。
用 response->redirect() 返回 302 重定向
这是最常用、语义最清晰的方式。Hyperf 的 ResponseInterface 提供了 redirect() 方法,底层调用的是 PSR-7 兼容的重定向逻辑:
- 它会自动设置
Status: 302和Location响应头 - 支持相对路径(如
/dashboard)、绝对路径(如https://example.com/login),也支持带查询参数(如/user?tab=profile) - 注意:不能在已写入响应体后调用(比如你已经
return $this->response->json(...),再调redirect()就无效)
示例:
public function login()
{
// 验证通过后跳转
return $this->response->redirect('/dashboard');
}
public function logout()
{
// 清除 session 后跳转到登录页,并带提示
return $this->response->redirect('/login?msg=logged_out');
}
为什么不用 header('Location: ...') 或 exit
手动写 header() + exit 看似简单,但在 Hyperf 协程环境下有严重风险:
- 协程上下文可能未正确清理,导致内存泄漏或后续请求拿到错误的 request/response 实例
- 绕过了 Hyperf 的中间件生命周期(比如日志中间件收不到这次响应记录)
- 无法被单元测试捕获(
redirect()返回的是可断言的ResponseInterface)
一句话:Hyperf 的 redirect() 是协程安全、可测试、可拦截的;手写 header 是裸奔。
前端表单提交后跳转,别在控制器里“硬跳”
如果你的场景是用户提交一个 HTML 表单(比如登录表单),期望提交后跳转到后台首页,那更推荐的做法是:
- 控制器只做业务处理(验证、存库、写 session),成功后返回
200JSON(如{"code":0,"redirect":"/dashboard"}) - 前端 JS 拿到响应后,用
window.location.href = data.redirect跳转 - 或者更规范地:服务端直接返回
303 See Other,强制浏览器以 GET 方式跳转——这能天然防止刷新重复提交
Hyperf 默认 redirect() 发的是 302,如需 303,可显式指定:
return $this->response->withStatus(303)->withHeader('Location', '/dashboard');
不要试图在控制器里 render 模板再跳转
Hyperf 默认不带模板引擎(除非你额外装了 hyperf/view)。即使配了 Twig 或 Blade,控制器也不该先 fetch() 渲染一个页面,再“跳转”过去——那只是输出了一段 HTML,不是跳转。真正的跳转必须靠 Location 响应头驱动浏览器行为。
如果确实需要服务端渲染后跳转,唯一合理路径是:用 redirect() 跳到另一个只负责渲染的路由(比如 GET /dashboard),由那个路由去 view->fetch()。控制器职责必须单一:处理逻辑,决定下一步去哪,而不是既干活又画 UI。


















