php 请求 生命周期,Laravel 请求生命周期

本文主要介绍了一个 Http 请求在 Laravel 中是怎样处理的。

public/index.php

所有 Laravel 程序均起始于 public/index.php 文件。

define('LARAVEL_START', microtime(true));

require __DIR__.'/../vendor/autoload.php';

$app = require_once __DIR__.'/../bootstrap/app.php';

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(

$request = Illuminate\Http\Request::capture()

);

$response->send();

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

index 里的代码很简单,首先定义了一个常量 LARAVEL_START ,接着引入了 composer 库中的 autoloader。随后加载 Laravel 的 Application 实例。接着到了最重要的部分,通过 Http Kernel 处理请求,最后将响应进行返回。

处理请求

在这里我们具体关注 Http Kernel 是怎样处理请求的。在 Illuminate\Foundation\Http\Kernel 中我们看到有 handle 方法。具体如下:

public function handle($request)

{

try {

$request->enableHttpMethodParameterOverride();

$response = $this->sendRequestThroughRouter($request);

} catch (Exception $e) {

$this->reportException($e);

$response = $this->renderException($request, $e);

} catch (Throwable $e) {

$this->reportException($e = new FatalThrowableError($e));

$response = $this->renderException($request, $e);

}

$this->app['events']->dispatch(

new Events\RequestHandled($request, $response)

);

return $response;

}

在上面的代码中,首先我们对 Http 方法确保能够进行覆盖处理,具体的用途参考这里,接着 Laravel 将请求通过sendRequestThroughRouter 进行处理。

protected function sendRequestThroughRouter($request)

{

$this->app->instance('request', $request);

Facade::clearResolvedInstance('request');

$this->bootstrap();

return (new Pipeline($this->app))

->send($request)

->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)

->then($this->dispatchToRouter());

}

在这里我们实例化 \Illuminate\Http\Request,然后引导相关的引导程序类,具体如下:

protected $bootstrappers = [

\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, // 加载env环境变量

\Illuminate\Foundation\Bootstrap\LoadConfiguration::class, // 加载配置文件

\Illuminate\Foundation\Bootstrap\HandleExceptions::class, // 异常处理

\Illuminate\Foundation\Bootstrap\RegisterFacades::class, // 注册 Facades

\Illuminate\Foundation\Bootstrap\RegisterProviders::class, // 注册 Providers

\Illuminate\Foundation\Bootstrap\BootProviders::class, // 启动 Providers

];

public function bootstrap()

{

if (! $this->app->hasBeenBootstrapped()) {

$this->app->bootstrapWith($this->bootstrappers());

}

}

protected function bootstrappers()

{

return $this->bootstrappers;

}

引导完毕之后,通过管道(pipeline)进行请求处理。关于管道的原理会在后面的文章中进行分析,这里你可以理解为循环使用中间件来处理请求。当所有的中间件处理完之后,交由dispatchToRouter进行下一步处理。

匹配路由

// Kernel.php

protected function dispatchToRouter()

{

return function ($request) {

$this->app->instance('request', $request);

return $this->router->dispatch($request);

};

}

// Illuminate\Routing\Router

public function dispatch(Request $request)

{

$this->currentRequest = $request;

return $this->dispatchToRoute($request);

}

public function dispatchToRoute(Request $request)

{

return $this->runRoute($request, $this->findRoute($request));

}

protected function findRoute($request)

{

$this->current = $route = $this->routes->match($request);

$this->container->instance(Route::class, $route);

return $route;

}

protected function runRoute(Request $request, Route $route)

{

$request->setRouteResolver(function () use ($route) {

return $route;

});

$this->events->dispatch(new Events\RouteMatched($route, $request));

return $this->prepareResponse($request,

$this->runRouteWithinStack($route, $request)

);

}

protected function runRouteWithinStack(Route $route, Request $request)

{

$shouldSkipMiddleware = $this->container->bound('middleware.disable') &&

$this->container->make('middleware.disable') === true;

$middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);

return (new Pipeline($this->container))

->send($request)

->through($middleware)

->then(function ($request) use ($route) {

return $this->prepareResponse(

$request, $route->run()

);

});

}

public function prepareResponse($request, $response)

{

return static::toResponse($request, $response);

}

public static function toResponse($request, $response)

{

if ($response instanceof Responsable) {

$response = $response->toResponse($request);

}

if ($response instanceof PsrResponseInterface) {

$response = (new HttpFoundationFactory)->createResponse($response);

} elseif (! $response instanceof SymfonyResponse &&

($response instanceof Arrayable ||

$response instanceof Jsonable ||

$response instanceof ArrayObject ||

$response instanceof JsonSerializable ||

is_array($response))) {

$response = new JsonResponse($response);

} elseif (! $response instanceof SymfonyResponse) {

$response = new Response($response);

}

if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED) {

$response->setNotModified();

}

return $response->prepare($request);

}

// Illuminate\Routing\Route

public function run()

{

$this->container = $this->container ?: new Container;

try {

if ($this->isControllerAction()) {

return $this->runController();

}

return $this->runCallable();

} catch (HttpResponseException $e) {

return $e->getResponse();

}

}

在上面的代码中,我们首先要找到匹配的路由,即findRoute方法。其中 match 方法的大致逻辑为:

获取到当前程序中的所有路由地址

对比 uri,http 方法,scheme 和 host

返回符合条件的第一个路由

如果未找到抛出异常

如果找到了匹配的路由,触发路由匹配事件,随后在 runRouteWithinStack 中,我们继续使用管道处理。接着在 $route->run() 中返回结果(根据是控制器方法还是回调方法分别进行处理)。最后根据不同的响应类型和状态设置不同的 Header 和 请求结果。

至此 Laravel 的请求生命周期基本结束。以后的文章会继续研究 Laravel 的其他功能原理。

本作品采用《CC 协议》,转载必须注明作者和本文链接

There's nothing wrong with having a little fun.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值