2026 年 7 月 29 日 · 阅读时长 8 分钟

Laravel 13 请求生命周期:从入口文件到响应终止

一条路由可能只有几行代码,但一次 HTTP 请求到达 Controller 前,已经经历应用创建、配置加载、Service Provider 注册、全局 middleware 和路由匹配。Controller 返回结果后,Response 还会沿 middleware 调用栈向外传递,最后进入 HTTP Kernel 的终止阶段。

Laravel 13 延续 Laravel 11 引入的精简应用结构。新项目不再默认提供 app/Http/Kernel.phpApp\Providers\RouteServiceProvider,应用级 middleware、异常处理和路由文件统一在 bootstrap/app.php 中配置。沿用旧版本的目录结构,容易误判请求从哪里进入 Kernel、路由又在何时加载。

本文以 Laravel 13 默认应用骨架与 laravel/framework 13.x 分支为基准。Laravel 13 于 2026 年 3 月 17 日发布,最低要求 PHP 8.3。

一次请求经过哪些阶段

请求进入时依次经过全局 middleware 与路由 middleware,Response 生成后再按相反方向返回。Response::send() 完成后,Kernel 才调用 terminable middleware 的 terminate();它不在普通 handle() 的调用链内。

public/index.php 创建应用并捕获请求

Web Server 会把动态请求转发到 public/index.php。默认入口依次完成四项工作:

  1. 定义请求开始时间 LARAVEL_START

  2. 检查 storage/framework/maintenance.php,必要时直接返回预渲染的维护响应。

  3. 加载 Composer 生成的 autoloader。

  4. bootstrap/app.php 取得 Application,捕获当前 HTTP 请求并交给应用处理。

Laravel 13 默认骨架的入口末尾调用 Application::handleRequest()

/** @var Application $app */
$app = require_once __DIR__.'/../bootstrap/app.php';

$app->handleRequest(Request::capture());

Request::capture() 根据当前 PHP 请求环境创建 Illuminate\Http\RequestApplication::handleRequest() 从 Service Container 解析实现了 Illuminate\Contracts\Http\Kernel 的 HTTP Kernel,再把请求交给 handle()

Application 同时也是 Laravel 的 Service Container。Controller、middleware、Service Provider 和其他框架服务后续都通过这个容器创建或解析。

bootstrap/app.php 定义应用的启动方式

Laravel 13 的默认 bootstrap/app.php 使用 Application::configure() 构建应用:

use Illuminate\Http\Request;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        //
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        $exceptions->shouldRenderJsonWhen(
            fn (Request $request) => $request->is('api/*') || $request->expectsJson(),
        );
    })->create();

withRouting() 声明 Web、API、Console、Broadcasting 或健康检查路由;withMiddleware() 调整全局 middleware、middleware group、alias 与优先级;withExceptions() 配置异常的 report 与 render 行为。create() 返回配置完成的应用实例。

这些方法注册配置回调。应用实例创建后,完整的框架 bootstrap 仍由 HTTP Kernel 在处理请求时完成。

HTTP Kernel 先完成 bootstrap

Illuminate\Foundation\Http\Kernel::handle() 先记录请求开始时间,再调用 sendRequestThroughRouter()。该方法把当前 Request 写入 Service Container,清理 Request Facade 的旧解析结果,并运行以下 bootstrappers:

LoadEnvironmentVariables
LoadConfiguration
HandleExceptions
RegisterFacades
RegisterProviders
BootProviders

这些 bootstrappers 依次加载环境变量与配置、建立异常处理、注册 Facade、注册 Service Provider,再启动已经注册的 Service Provider。日志、数据库、缓存、队列、验证和路由等框架能力,也在此时取得所需的容器绑定与配置。

HandleExceptions 建立框架级异常处理。middleware、路由或 Controller 抛出未处理异常时,HTTP Kernel 会 report 异常,再根据 bootstrap/app.php 中的配置将其 render 为 HTTP Response。404 同样由这套机制转换为 Response。

Service Provider 先 register(),再 boot()

Laravel 13 把应用自定义和第三方 Service Provider 列在 bootstrap/providers.php

return [
    App\Providers\AppServiceProvider::class,
];

框架自身还会加载内部默认 Service Provider。Laravel 会先实例化并调用各个 Provider 的 register(),所有注册工作完成后,再调用它们的 boot()

register() 负责向 Service Container 注册 binding、singleton 或其他服务定义,此时不应依赖另一个 Provider 尚未注册的服务。执行 boot() 时,其他非延迟 Provider 的容器绑定已经可用,路由、事件监听器、view composer 等依赖外部服务的启动逻辑可以开始运行。

部分只提供容器 binding 的 Provider 可以实现 DeferrableProvider。这类 Provider 不必在每个请求中立即加载,相关服务第一次从容器解析时才会注册。

默认应用也不再要求自建 App\Providers\RouteServiceProviderbootstrap/app.phpwithRouting() 会把路由加载回调交给框架内部的 Route Service Provider,在应用 boot 时加载 routes/web.php 等文件;启用 route cache 后,则直接加载缓存路由。

全局 middleware 包住 Router

应用完成 bootstrap 后,HTTP Kernel 把 Request 送入由全局 middleware 组成的 Pipeline,Pipeline 末端是 Router:

return (new Pipeline($this->app))
    ->send($request)
    ->through($this->middleware)
    ->then($this->dispatchToRouter());

默认全局 middleware 会处理路径编码、延迟回调、可信代理、CORS、维护模式、请求体大小和输入规范化等工作。应用可在 bootstrap/app.php 中追加、前置、替换或移除它们。

Session 和 CSRF 防护位于 web middleware group,不属于默认全局 stack。routes/web.phpwithRouting() 自动放入 web group,因此浏览器路由通常会经过 Cookie、Session、共享验证错误、请求伪造防护和 route model binding。api group 的默认内容更少,应用安装 API 路由后可按需加入限流、认证或状态化 API middleware。

Middleware 可以提前返回 Response。维护模式、认证失败、限流或自定义校验一旦中止请求,Router 或 Controller 就不会执行。

Router 先匹配 Route,再运行路由 middleware

Request 通过全局 middleware 后,Router 根据 HTTP method、domain 和 URI 从 RouteCollection 中查找匹配项。匹配成功后,Laravel 把当前 Route 绑定到 Request 和 Service Container,并触发 RouteMatched event。

Router 随后收集 Route 自身声明的 middleware、middleware group 和 Controller middleware,按优先级排序后创建路由 middleware Pipeline。SubstituteBindings 通常在这里完成显式与隐式 route model binding,因此 Controller 接收的参数可能已经是 Eloquent Model。

没有 Route 能匹配时,Router 抛出 NotFoundHttpException。异常处理器将它转换为 404 Response,Controller 不会执行。

Controller 由 Service Container 创建

Route 通过全部路由 middleware 后,Route::run() 执行 Closure 或 Controller action。ControllerDispatcher 会先解析路由参数和方法依赖,再调用目标方法:

public function show(Request $request, Order $order): JsonResponse
{
    return response()->json([
        'id' => $order->id,
        'status' => $order->status,
    ]);
}

Request 由 Service Container 注入,Order 通常来自 route model binding,Controller 构造函数中的依赖也由容器解析。Controller 负责协调应用服务并返回结果,最终的 Symfony Response 由框架创建。

Route 或 Controller 可以返回 Response、View、字符串、数组、Eloquent Model、实现 Responsable 的对象或 PSR-7 Response。Router 的 prepareResponse()toResponse() 会把这些返回值规范化为 Symfony\Component\HttpFoundation\Response。新建的 Eloquent Model 会转换为状态码 201 的 JSON Response,其他常见数组和 Model 返回值会转换为 JSON Response。

响应沿 middleware 向外返回

Middleware 的核心结构是调用 $next($request)

public function handle(Request $request, Closure $next): Response
{
    $response = $next($request);

    $response->headers->set('X-Request-Stage', 'handled');

    return $response;
}

请求进入时,middleware 从外到内依次调用。Controller 生成 Response 后,调用栈按相反方向展开:路由 middleware 先取得 Response,全局 middleware 随后取得 Response。它们可以修改 header、Cookie 或 body,也可以记录处理结果。

每个 middleware 的 handle() 只执行一次:$next() 之前的代码处理进入阶段,$next() 之后的代码处理返回阶段。全局 Pipeline 完成后,HTTP Kernel 触发 RequestHandled event,并把最终 Response 返回给 Application::handleRequest()

先发送响应,再执行终止阶段

Application::handleRequest() 按以下顺序发送并终止请求:

$response = $kernel->handle($request)->send();

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

send() 发送 HTTP header 与响应内容。使用 PHP-FPM / FastCGI 时,Web Server 可以先把响应交给客户端,PHP 进程再继续执行终止阶段。

HTTP Kernel 的 terminate() 会触发 Terminating event,收集当前 Route 和全局 stack 中的 middleware,只对定义了 terminate(Request $request, Response $response) 的类调用终止方法。随后,Laravel 执行应用级 terminating callbacks 和请求耗时监控回调。

需要在响应发送后继续处理的 middleware,必须显式定义 terminate(),并注册到全局或路由 middleware 中。Laravel 默认会从 Service Container 重新解析 terminable middleware;若 handle()terminate() 必须共享同一实例,应把该 middleware 注册为 singleton。

终止阶段适合不影响客户端响应的短任务,比如补充访问日志。耗时、需要重试或不能丢失的工作仍应进入 Queue,不能依赖 PHP 进程在响应发送后长时间运行。

按源码顺序排查请求问题

一次请求没有进入预期 Controller 时,可以按这组顺序定位:

  1. public/index.php 是否被 Web Server 正确转发,应用是否停在 maintenance response。

  2. bootstrap/app.php 是否加载了目标路由文件,middleware 和异常规则是否正确。

  3. HTTP Kernel bootstrap 是否在配置、Provider 注册或 Provider boot 阶段失败。

  4. 全局 middleware 是否提前返回了 Response。

  5. Router 是否匹配到预期 method、domain 和 URI。

  6. 路由 middleware、认证、权限或 model binding 是否中止请求。

  7. Controller 依赖是否能从 Service Container 解析,action 是否返回了可转换的结果。

  8. 响应是否在 middleware 返回阶段被修改,发送后任务是否只放在 terminate() 或 Queue 中。

对应的 framework 源码入口依次是 Application::handleRequest()Http\Kernel::handle()Http\Kernel::sendRequestThroughRouter()Router::dispatchToRoute()Router::runRouteWithinStack()Route::run()Router::prepareResponse()Http\Kernel::terminate()。沿这组方法设置断点,比从 Controller 反向猜测更容易确认请求停在哪一层。

相关内容

参考资料

CO

我是 Cooper,一名生活在中国的开发者,多年来一直在家远程工作。

主要使用 Go、PHP 和 Rust,从事移动端、Web、跨境支付与资金系统开发。目前主要采用 Vibe Coding 构建产品,并以真实运行结果完成验证与交付。