请求的生命周期
用任何工具,搞懂它怎么运作的心里才踏实。写代码也一样——你得知道框架在背后做了什么,用起来才不慌。
这篇从宏观上带你走一遍 Laravel 框架的运作流程。了解整体机制后,很多"魔法"就不神了,写代码也会更有底气。有些术语一时看不懂没关系,先有个大致印象,后面翻别的章节会越看越明白。
生命周期概览 (这里可以打开源码对着看)
第一步:入口
所有请求的入口都是 public/index.php。你的 Web 服务器(Apache / Nginx)配置会把每个请求都指向这个文件。index.php 本身没什么代码——它是个起点,负责把框架的其余部分加载起来。
index.php 先加载 Composer 生成的自动加载文件,然后从 bootstrap/app.php 拿到 Laravel 应用实例。Laravel 做的第一件事,就是创建这个应用实例 / 服务容器。
HTTP / Console 内核
接下来,根据请求类型(HTTP 请求还是命令行)应用实例的 handleRequest 或 handleCommand 方法会把请求分别交给 HTTP 内核或 Console 内核。这两个内核是所有请求流转的中央枢纽。这里我们只看 HTTP 内核,它是 Illuminate\Foundation\Http\Kernel 的实例。
HTTP 内核里定义了一组 bootstrappers(引导程序),在真正处理请求之前依次执行。这些引导程序负责配置错误处理、日志系统、检测应用环境等前置工作。基本上都是框架内部的配置活儿,不用你操心。
HTTP 内核还负责让请求穿过应用的中间件栈。中间件做的事包括读写 HTTP Session、判断应用是否处于维护模式、校验 CSRF 令牌 等等。后面会细讲。
HTTP 内核的 handle() 方法的签名很简单:接收一个 Request,返回一个 Response。你可以把内核想象成一个黑盒子——它代表你的整个应用,喂 HTTP 请求进去,吐出 HTTP 响应。
服务提供者
内核引导过程中最重要的一步,就是加载服务提供者。服务提供者负责引导框架的各个组件——数据库、队列、验证、路由等,几乎所有功能都是靠它启动的。
Laravel 会遍历服务提供者列表,逐个实例化。实例化之后先对所有提供者调用 register() 方法,全部注册完成后再逐个调用 boot() 方法。这个顺序保证了 boot() 执行时,所有容器的绑定都已经注册好、可以用了。
Laravel 的每个核心功能,基本都是由某个服务提供者来引导和配置的。正因为它们引导了这么多东西,服务提供者是整个 Laravel 启动流程里最重要的环节。
框架内部自己就用了几十个服务提供者,你也可以写自己的。你的应用用了哪些自定义或第三方服务提供者,去 bootstrap/providers.php 文件里就能看到列表。
路由
应用引导完成、所有服务提供者注册完毕之后,Request 被交给路由器来处理。路由器把请求分发到对应的路由或控制器,同时执行路由专属的中间件。
中间件提供了一种灵活的机制,用来过滤或检查进入应用的 HTTP 请求。比如 Laravel 内置的认证中间件会检查用户是否已登录——没登录就跳转到登录页,已登录就放行。有的中间件作用于所有路由(比如维护模式检测 PreventRequestsDuringMaintenance),有的只挂到特定路由或路由组上。详见中间件文档。
请求穿过匹配路由的所有中间件后,路由或控制器方法被执行。它返回的响应再沿着中间件链往回传。
收尾
路由或控制器方法返回响应后,响应会沿着中间件链层层向外回传,每一层都有机会修改或检查这个响应。
最终,响应穿过所有中间件后,HTTP 内核的 handle() 方法把响应对象交给应用实例的 handleRequest(),后者调用响应的 send() 方法——这一步把响应内容真正发给用户的浏览器。一个完整的 Laravel 请求生命周期,到此结束!
聚焦服务提供者
服务提供者是 Laravel 应用启动的关键。应用实例创建 → 服务提供者注册 → 请求交给已引导好的应用,就这么简单。
搞懂「Laravel 应用是如何通过服务提供者一步步构建和启动的」这一点非常重要。你的自定义服务提供者在 app/Providers 目录下。
默认的 AppServiceProvider 基本是空的。它是你加引导逻辑和容器绑定的好地方。应用大的话可以建多个服务提供者,每个负责一类服务,粒度更细。