Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

01. HTTP 入口解析 #1

Open
xiaohuilam opened this issue Sep 25, 2018 · 2 comments
Open

01. HTTP 入口解析 #1

xiaohuilam opened this issue Sep 25, 2018 · 2 comments
Labels
book The digital book for laravel learning

Comments

@xiaohuilam
Copy link
Owner

xiaohuilam commented Sep 25, 2018

HTTP 入口解析

public/index.php 入口

public/index.php 中第 24 行

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

逻辑为,引入 ../vendor/autoload.php,即 composer 产生的 vendor/autoload.php

接着第 38 行

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

这里面做的事情不少,具体的我们看 bootstrap/app.php 的代码。

bootstrap/app.php 实例化容器

在第 [14-16行]

$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);

这是 Laravel 框架内为数不多的直接 new 出来的对象,也就是框架的应用对象,
此对象继承于 Illuminate\Container\Container (容器),
所以, Laravel 框架中的容器对象一般就是指的 Illuminate\Foundation\Application 对象(因在实际运行过程中,不会直接 new Illuminate\Container\Container 的)。

在第 [29-42行]

$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);

这里的singleton是 public/index.php 中,用 Illuminate\Contracts\Http\Kernel 能注入后取出 App\Http\Kernel 的关键。

关于 singleton() 的解析,请见 10. 容器的 singleton 和 bind 的实现

第 55行

return $app;

在前面 public/index.php 中的

$app = require_once __DIR__.'/../bootstrap/app.php';
拿到了 return$app

public/index.php 构建 + 处理

public/index.php 第 52 行

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

这里调用了 Illuminate\Foundation\Application 的 make 方法(具体解析请见本篇结尾的链接),获得了 http 处理器 ( $kernel )

然后第 54-56 行

laravel/public/index.php

Lines 54 to 56 in 7028b17

$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);

先用 Illuminate\Http\Request::capture() 抓出一个 Illuminate\Http\Request HTTP请求对象

Request::capture 请求捕获

Illuminate\Http\Request::capture() 的代码为

public static function capture()
{
static::enableHttpMethodParameterOverride();
return static::createFromBase(SymfonyRequest::createFromGlobals());
}

其中调用了 Symfony\Component\HttpFoundation\Request::createFromGlobals()

public static function createFromGlobals()
{
$request = self::createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER);
if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded')
&& \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), array('PUT', 'DELETE', 'PATCH'))
) {
parse_str($request->getContent(), $data);
$request->request = new ParameterBag($data);
}
return $request;
}

其作用是讲 HTTP 请求过来的参数,按照 key => value 格式生成 Symfony\Component\HttpFoundation\ParameterBag 对象。
然后将包含 ParameterBag$request 对象交给 Illuminate\Http\Request::createFromBase()
public static function createFromBase(SymfonyRequest $request)
{
if ($request instanceof static) {
return $request;
}
$content = $request->content;
$request = (new static)->duplicate(
$request->query->all(), $request->request->all(), $request->attributes->all(),
$request->cookies->all(), $request->files->all(), $request->server->all()
);
$request->content = $content;
$request->request = $request->getInputSource();
return $request;
}

(new static)->duplicate() 最终执行了

public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null)
{
$dup = clone $this;
if (null !== $query) {
$dup->query = new ParameterBag($query);
}
if (null !== $request) {
$dup->request = new ParameterBag($request);
}
if (null !== $attributes) {
$dup->attributes = new ParameterBag($attributes);
}
if (null !== $cookies) {
$dup->cookies = new ParameterBag($cookies);
}
if (null !== $files) {
$dup->files = new FileBag($files);
}
if (null !== $server) {
$dup->server = new ServerBag($server);
$dup->headers = new HeaderBag($dup->server->getHeaders());
}
$dup->languages = null;
$dup->charsets = null;
$dup->encodings = null;
$dup->acceptableContentTypes = null;
$dup->pathInfo = null;
$dup->requestUri = null;
$dup->baseUrl = null;
$dup->basePath = null;
$dup->method = null;
$dup->format = null;
if (!$dup->get('_format') && $this->get('_format')) {
$dup->attributes->set('_format', $this->get('_format'));
}
if (!$dup->getRequestFormat(null)) {
$dup->setRequestFormat($this->getRequestFormat(null));
}
return $dup;
}

其将重要的 http 请求头、请求参数、请求文件、cookie 等信息赋给相应属性。

在后面的

$request->request = $request->getInputSource();

Request::getInputSource() 的代码是
protected function getInputSource()
{
if ($this->isJson()) {
return $this->json();
}
return in_array($this->getRealMethod(), ['GET', 'HEAD']) ? $this->query : $this->request;
}

作用是调用 $request->input() 之时

GET、HEAD 请求,能取到 GET 参数,
POST 请求,能取到 POST 参数。

至此,Request::capture() 就执行完了。

public/index.php 运行逻辑

然后交给 App\Http\Kernelhandle 方法进行处理,获得 $response (Illuminate\Http\Request 对象)。

Laravel 框架的设计绝大可扩展部分(如服务提供者、中间件)都是在这个阶段处理和触发的,
所以我单独把 02. HTTP Kernel Handle 解析 拆出去了。

最后,在第 58-60行

laravel/public/index.php

Lines 58 to 60 in 7028b17

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

调用 Illuminate\Http\Response 的 send 方法,将响应的状态码/头/内容返回给客户端(浏览器),具体过程可见本篇末尾的引用。


@xiaohuilam xiaohuilam added the book The digital book for laravel learning label Sep 25, 2018
@xiaohuilam xiaohuilam changed the title 01. HTTP入口解析 01. HTTP 入口解析 Sep 26, 2018
@mitoop
Copy link

mitoop commented Apr 10, 2019

其作用是讲 HTTP 请求过来的参数,按照 key => value 格式生成 Symfony\Component\HttpFoundation\ParameterBag 对象。
然后将包含 ParameterBad 的 $request 对象交给 Illuminate\Http\Request::createFromBase()

ParameterBad 错别字 => ParameterBag

@wdzhjj
Copy link

wdzhjj commented Oct 23, 2019

很详细,牛b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
book The digital book for laravel learning
Projects
None yet
Development

No branches or pull requests

3 participants