信息发布→ 登录 注册 退出

一个HTTP请求在Laravel中完整的生命周期是怎样的? (index.php到Response)

发布时间:2026-01-14

点击量:
Laravel请求生命周期始于public/index.php加载自动加载器和应用实例,经HttpKernel::handle()启动,按bootstrap→中间件栈(洋葱模型)→路由分发→控制器中间件二次执行→响应发送→terminate()异步钩子顺序执行。

public/index.php 开始:入口文件只做两件事

它不处理路由、不解析请求,只负责加载自动加载器和启动应用实例。核心就两行:

require __DIR__.'/../vendor/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';

注意:bootstrap/app.php 返回的是 Illuminate\Foundation\Application 实例,不是 HTTP kernel。真正的请求分发还没开始。

Kernel::handle() 是请求生命周期的真正起点

public/index.php 末尾你会看到:

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

这个 $kernelApp\Http\Kernel,继承自 Illuminate\Foundation\Http\Kernel。它内部按顺序执行:

  • bootstrap():初始化配置、日志、异常处理器等(只在首次请求触发)
  • sendRequestThroughRouter():关键路径 —— 把请求塞进中间件栈 + 路由分发管道

中间件栈分三类:$middleware(全局)、$middlewareGroups(如 web)、$routeMiddleware(路由级)。它们不是并行执行,而是洋葱模型嵌套调用。

路由匹配后:控制器方法执行前还有一次中间件穿透

当路由找到对应控制器方法(比如 PostController@edit),Laravel 并不会直接调用它。而是先用 Illuminate\Routing\Router 构建一个 Illuminate\Routing\ControllerDispatcher,再把请求再次交给该控制器绑定的中间件(通过 __construct()middleware() 方法注册)。

这意味着:同一个请求可能被同一中间件执行两次(一次在 Kernel 全局栈,一次在控制器局部栈),尤其容易在日志、权限校验类中间件里引发重复副作用。

常见坑:auth 中间件如果同时出现在全局栈和控制器上,会导致 Auth::user() 在第二次执行时因 session 已读取而返回 null 或缓存旧值。

响应生成后:Kernel::terminate() 不是“收尾”,而是异步钩子

你可能会在 public/index.php 看到:

$kernel->terminate($request, $response);

但它**不参与响应发送过程**。HTTP 响应体早已由 $response->send() 输出到 SAPI(如 PHP-FPM 的 stdout)。terminate() 只用于触发那些“无需阻塞用户等待”的操作,比如:

  • 写入慢查询日志(但不能依赖它保证日志落盘)
  • 触发队列任务(dispatchNow() 安全,dispatch() 可能失败)
  • 关闭数据库连接(DB::disconnect()

注意:terminate() 中抛出的异常不会影响已发出的响应,也几乎不会被开发者感知 —— 它常被误当成“清理资源的可靠时机”,其实只是尽力而为。

标签:# php  # laravel  # bootstrap  # 处理器  # app  # session  #   # 路由  # 中间件  # NULL  
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!