Laravel: Laravel请求生命周期与HTTP内核

最后更新:2026-08-26

请求生命周期是 Laravel 的"引擎原理图"——理解它,你就从"会用框架"升级到"懂框架"。

1. 你将学到


2. 一个高级开发者的真实故事

(1) 痛点:黑盒调试浪费数小时

Alice 在 ShopMetrics 遇到一个怪 Bug:本地没问题,上线后某个 Facade 返回 null。她不知道 Facade 底层调用的是哪个类,也不清楚服务容器在哪里绑定的。花了 4 小时翻代码才发现,一个 ServiceProvider 的 register() 方法有条件判断,生产环境分支没有注册绑定。Bob 也吃过亏——他不理解中间件执行顺序,导致认证中间件排在 CORS 之后,预检请求直接 401。

(2) 理解生命周期的解法

理解请求生命周期后,你能精确定位任何问题发生在哪个阶段——是路由没匹配、中间件没通过、容器绑定缺失,还是 Provider 没加载。

PHP
// Knowing the lifecycle helps you debug like this:
// 1. Check if the binding exists
app()->bound('payment.gateway');
// 2. Check which provider registered it
app()->getBindings()['payment.gateway']['concrete'];
// 3. Trace middleware execution order
app()->make(\Illuminate\Foundation\Http\Kernel::class)->getMiddlewarePriority();

(3) 收益

Alice 用容器调试技巧 5 分钟定位了 Facade 返回 null 的原因,Bob 调整了中间件优先级后 CORS 问题立刻解决。理解生命周期的开发者,调试效率提升 10 倍。


3. 请求生命周期

(1) 完整流程

100%
flowchart TD
    A["public/index.php<br/>(Entry Point)"] --> B["HTTP Kernel<br/>(bootstrap/app.php)"]
    B --> C["Service Providers<br/>(Register & Boot)"]
    C --> D["Middleware Pipeline<br/>(Global + Route)"]
    D --> E{"Route Matched?"}
    E -->|Yes| F["Controller/Action<br/>(Business Logic)"]
    E -->|No| G["Fallback/404"]
    F --> H["Response Object"]
    G --> H
    H --> I["Send to Client"]
    I --> J["Terminate<br/>(Post-response hooks)"]

(2) 各阶段详解

阶段 文件/类 职责
入口 public/index.php 加载 Composer autoload,创建应用实例
内核 bootstrap/app.php 配置中间件、异常处理、路由
Provider 注册 config/app.providers 注册容器绑定
Provider 启动 Provider boot() 执行启动逻辑
中间件 Global → Route 过滤/修改请求和响应
路由分发 Router 匹配 URL → 执行控制器
终止 Terminable Middleware 响应后执行清理操作

▶ 示例:查看请求生命周期各阶段

BASH
# Check registered service providers
php artisan about --only=providers
# Listed: AppServiceProvider, AuthServiceProvider, etc.

# Check middleware pipeline
php artisan route:list --columns=method,uri,middleware
# GET /dashboard → auth, tenant.resolve, verified

# Check bound services in container
php artisan tinker
# app()->getBindings()
# Lists all registered container bindings

输出:

TEXT 📖 仅展示
# 命令执行成功

4. HTTP Kernel 与 Console Kernel

Laravel 有两个内核:HTTP 内核处理 Web 请求,Console 内核处理 Artisan 命令。

(1) Laravel 11 的 Kernel 配置

PHP
// bootstrap/app.php — Laravel 11 single-file configuration
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->appendToGuestList([
            '/api/*',
        ]);
        $middleware->alias([
            'tenant.resolve' => \App\Http\Middleware\TenantResolve::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();
维度 HTTP Kernel Console Kernel
入口 public/index.php artisan 文件
处理对象 HTTP Request Console Input
中间件 Global + Route
输出 HTTP Response Console Output
环境 Web 请求 CLI 命令

▶ 示例:自定义全局中间件

PHP
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    // Add global middleware (runs on every request)
    $middleware->append([
        \App\Http\Middleware\SetLocale::class,
    ]);

    // Remove a default global middleware
    $middleware->remove([
        \Illuminate\Foundation\Http\Middleware\TrimStrings::class,
    ]);

    // Register alias for route middleware
    $middleware->alias([
        'tenant' => \App\Http\Middleware\TenantResolve::class,
        'role' => \App\Http\Middleware\CheckRole::class,
    ]);
})

输出:

TEXT 📖 仅展示
// 执行成功

5. 服务容器

服务容器是 Laravel 的核心——它管理类的依赖注入和生命周期。

(1) 绑定

PHP
// app/Providers/AppServiceProvider.php
public function register(): void
{
    // Bind interface to implementation
    $this->app->bind(
        PaymentGatewayInterface::class,
        StripeGateway::class,
    );

    // Bind with closure (full control)
    $this->app->bind('analytics.service', function ($app) {
        return new AnalyticsService(
            $app->make(CacheManager::class),
            $app['config']->get('analytics.ttl'),
        );
    });

    // Singleton — same instance every time
    $this->app->singleton(ShopMetricsConfig::class, function ($app) {
        return new ShopMetricsConfig(
            $app['config']->get('shopmetrics'),
        );
    });
}
绑定方式 每次调用 用途
bind() 创建新实例 无状态服务
singleton() 复用实例 有状态/昂贵对象
scoped() 每请求新实例 请求级单例
instance() 使用现有实例 已创建的对象

(2) 解析

PHP
// Automatic resolution via type-hint
class OrderController extends Controller
{
    public function __construct(
        private PaymentGatewayInterface $gateway, // auto-resolved
    ) {}
}

// Manual resolution
$gateway = app(PaymentGatewayInterface::class);
$gateway = app()->make(PaymentGatewayInterface::class);
$analytics = resolve('analytics.service');

▶ 示例:ShopMetrics 服务容器绑定

PHP
// app/Providers/AppServiceProvider.php
public function register(): void
{
    $this->app->bind(
        \App\Contracts\ReportGeneratorInterface::class,
        \App\Services\PdfReportGenerator::class,
    );

    $this->app->singleton(
        \App\Services\TenantManager::class,
        fn ($app) => new TenantManager(
            $app->make(\App\Models\Tenant::class),
        ),
    );

    $this->app->when(ShopController::class)
        ->needs(\App\Contracts\FileStorageInterface::class)
        ->give(\App\Services\S3StorageService::class);
}

输出:

TEXT 📖 仅展示
// 执行成功

6. Facades 原理

Facades 是 Laravel 的"静态代理"——用简洁的静态调用语法,背后通过服务容器解析实际对象。

(1) Facade 工作原理

100%
flowchart LR
    A["Cache::get('key')"] --> B["Cache Facade<br/>(static call)"]
    B --> C["Facade::__callStatic()"]
    C --> D["Resolve from Container<br/>(cache manager)"]
    D --> E["CacheManager->get('key')"]

(2) 常用 Facade 对应表

Facade 实际类 容器绑定键
Cache CacheManager cache
DB DatabaseManager db
Event Dispatcher events
Log LogManager log
Mail MailManager mail
Queue QueueManager queue
Route Router router
Storage FileManager filesystem

(3) Facade vs 依赖注入

维度 Facade 依赖注入
语法 静态调用 构造函数/方法注入
可测试性 可 Mock(Cache::fake() 可 Mock(手动绑定)
IDE 支持 需插件/辅助文件 原生类型提示
简洁性 ✅ 一行调用 ❌ 需构造函数声明
推荐场景 简单操作/控制器 Service 类/构造函数

▶ 示例:Facade 与依赖注入对比

PHP
// Using Facade — concise
use Illuminate\Support\Facades\Cache;

public function getShopStats(int $shopId): array
{
    return Cache::remember("shop.stats.{$shopId}", 3600, function () use ($shopId) {
        return Shop::findOrFail($shopId)->getStats();
    });
}

// Using DI — explicit, easier to test
public function __construct(
    private CacheManager $cache,
) {}

public function getShopStats(int $shopId): array
{
    return $this->cache->remember("shop.stats.{$shopId}", 3600, function () use ($shopId) {
        return Shop::findOrFail($shopId)->getStats();
    });
}

输出:

TEXT 📖 仅展示
// 执行成功

7. Service Provider 启动机制

(1) Provider 生命周期

TEXT 📖 仅展示
Request arrives
  → Register Phase: all providers' register() called (no booting yet)
  → Boot Phase: all providers' boot() called (all bindings available)
  → Application ready

(2) Deferred Provider

PHP
// app/Providers/PaymentServiceProvider.php
class PaymentServiceProvider extends ServiceProvider
{
    protected bool $defer = true;

    public function register(): void
    {
        $this->app->singleton(StripeGateway::class, function ($app) {
            return new StripeGateway(config('services.stripe'));
        });
    }

    public function provides(): array
    {
        return [StripeGateway::class];
    }
}
Provider 类型 何时加载 适用场景
普通 Provider 每次请求都加载 核心/常用功能
Deferred Provider 首次使用时加载 昂贵/低频功能

▶ 示例:ShopMetrics 自定义 ServiceProvider

PHP
// app/Providers/ShopMetricsServiceProvider.php
class ShopMetricsServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(
            ReportGeneratorInterface::class,
            PdfReportGenerator::class,
        );

        $this->app->singleton(TenantManager::class);
    }

    public function boot(): void
    {
        // Register middleware alias
        $this->app->make(\Illuminate\Routing\Router::class)
            ->aliasMiddleware('tenant', TenantResolve::class);

        // Register view composer
        View::composer('dashboard.*', NavigationComposer::class);

        // Register event listeners
        Event::listen(OrderPlaced::class, SendOrderNotification::class);
    }
}

输出:

TEXT 📖 仅展示
// 执行成功

8. 综合示例:ShopMetrics 请求追踪

PHP
// ============================================
// Comprehensive: Trace a ShopMetrics request
// Covers: lifecycle, container, facade, provider
// ============================================

// 1. public/index.php — Entry point
// $app = require_once __DIR__.'/../bootstrap/app.php';
// $app->handleRequest();

// 2. bootstrap/app.php — Kernel configuration
// return Application::configure(basePath: dirname(__DIR__))
//     ->withRouting(web: ..., api: ...)
//     ->withMiddleware(fn ($m) => $m->append([SetLocale::class]))
//     ->create();

// 3. AppServiceProvider — Register bindings
// public function register(): void
// {
//     $this->app->singleton(TenantManager::class);
//     $this->app->bind(PaymentGatewayInterface::class, StripeGateway::class);
// }

// 4. Route: GET /{tenant}/dashboard
// Route::middleware(['auth', 'tenant'])->get('/{tenant}/dashboard', [DashboardController::class, 'index']);

// 5. Controller — Use DI and Facades
class DashboardController extends Controller
{
    public function __construct(
        private TenantManager $tenantManager, // DI resolved
    ) {}

    public function index(Request $request): View
    {
        $tenant = $this->tenantManager->current();
        $stats = Cache::remember("dashboard.{$tenant->id}", 300, function () use ($tenant) {
            return [
                'revenue' => $tenant->shops()->sum('revenue'),
                'orders' => $tenant->orders()->count(),
                'shops' => $tenant->shops()->active()->count(),
            ];
        });

        return view('dashboard.index', compact('tenant', 'stats'));
    }
}

// 6. Response sent → Terminable middleware runs → Request complete

❓ 常见问题

Q Facade 和 helper 函数哪个好?
A 两者底层调用同一个服务。Facade 可 Mock 测试(Cache::fake()),helper 更简洁(cache())。推荐:简单场景用 helper,需要 Mock 时用 Facade。
Q register 和 boot 有什么区别?
A register 只做容器绑定,不能依赖其他服务;boot 在所有 register 完成后执行,可以安全使用任何绑定。遵循"register 只绑定,boot 才启动"原则。
Q 什么时候用 singleton 什么时候用 bind?
A 无状态服务用 bind(每次新实例,如 PDF 生成器);有状态或初始化昂贵的服务用 singleton(如数据库连接、缓存管理器)。
Q Deferred Provider 会不会导致首次请求慢?
A 会有一点首次加载开销,但整体减少每次请求的启动时间。如果某个功能 90% 的请求都不用,defer 是正确的选择。
Q 如何查看某个 Facade 对应的实际类?
A 查看 Facade 类的 getFacadeAccessor() 方法返回的字符串,然后在容器中查找对应的绑定。或者使用 app('cache') 直接获取实例。
Q Laravel 11 去掉了 Kernel.php 吗?
A 是的,Laravel 11 把 HTTP Kernel 和 Console Kernel 合并到 bootstrap/app.php,用链式 API 配置中间件、异常和路由。功能没变,只是配置更集中。

📖 小节


📝 作业

  1. 基础题(⭐):使用 php artisan about 查看 ShopMetrics 的 Service Provider 列表,识别哪些是框架默认的、哪些是自定义的,画出一个简化的请求生命周期流程图。

  2. 进阶题(⭐⭐):创建一个 ShopMetricsServiceProvider,用 bind() 绑定 ReportGeneratorInterfacePdfReportGenerator,然后在控制器中通过依赖注入使用它。

  3. 挑战题(⭐⭐⭐):实现一个 Deferred Provider,将 Stripe 支付网关延迟加载,用 provides() 声明提供的绑定,通过 app()->resolved() 验证它确实在首次使用时才加载。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏