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()
);
这个 $kernel 是 App\Http\Kernel,继承自 Illuminate\Foundation\Http\Kernel。它内部按顺序执行:
立即学习“PHP免费学习笔记(深入)”;
中间件栈分三类:$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() 中抛出的异常不会影响已发出的响应,也几乎不会被开发者感知 —— 它常被误当成“清理资源的可靠时机”,其实只是尽力而为。











