Skip to main content

终章 --- Response Send And Terminate

简介

终于。。。终章了。。。

上一章,完成响应头的设置后,最后一行的 return $this,就会把响应抛回入口文件,当然中间经过 EncryptCookies 这类中间件,会对响应进行再次处理。

让我们回到当年开始的地方,因为我们的初心在那里。。

public/index.php

// 省略上面一些不相关的代码...

/*
* handle 函数,你就是一个神仙,运行你,跑这么深的地方,到现在才回来。。。
* 行了,不吐槽了,$response 就是 `Symfony\Component\HttpFoundation\Response` 的实例化对象
*/
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);


// 将响应头和响应体返回给浏览器
$response->send();

// 调用所有在用中间件的终止函数,调用容器的终值函数,做 Laravel 最后的收尾工作。
$kernel->terminate($request, $response);

我们来看一下 Response 的 send 函数

Symfony\Component\HttpFoundation\Response

public function send()
{
// 调用 PHP 的 header 函数,将响应头数据全部返回给浏览器
$this->sendHeaders();

// 调用 PHP 的 echo 语句,将响应体数据加入到 PHP 的输出控制缓存中
$this->sendContent();

// 将 PHP 输出控制缓存中的数据返回给浏览器
if (\function_exists('fastcgi_finish_request')) {
fastcgi_finish_request();
} elseif (!\in_array(\PHP_SAPI, array('cli', 'phpdbg'), true)) {
static::closeOutputBuffers(0, true);
}

return $this;
}

sendHeaders 函数

Symfony\Component\HttpFoundation\Response

public function sendHeaders()
{
// headers_sent(),当 PHP 已发送响应头数据,返回 true,否则返回 false
if (headers_sent()) {
return $this;
}

// 从 Response 对象中获取响应头数据,使用 header 函数向浏览器输出 响应头
foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
foreach ($values as $value) {
header($name.': '.$value, false, $this->statusCode);
}
}

// 将 Cookies 返回给浏览器
foreach ($this->headers->getCookies() as $cookie) {
header('Set-Cookie: '.$cookie->getName().strstr($cookie, '='), false, $this->statusCode);
}

// 将类似 HTTP/1.0 200 success 这样的响应码信息,返回给浏览器
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);

return $this;
}

sendContent 函数

Symfony\Component\HttpFoundation\Response

public function sendContent()
{
// 不要误解,这里仅仅只是将 响应体 输出到 PHP 的控制输出缓存中,还没向浏览器发送数据。
echo $this->content;

return $this;
}

关于 PHP 的输出缓存控制

为什么要用缓存控制?

header 函数官方有一句话: 请注意 header() 必须在任何实际输出之前调用,不管是普通的 HTML 标签,还是文件或 PHP 输出的空行,空格。官方文档地址

这就造成一个问题,如果我们在 Laravel 控制器中 echo 一段内容,而框架假设没有使用 PHP 的输出控制,那么就会造成 响应头 无法发送到浏览器中。

关于输出控制怎么用

官方范例很好体现了输出缓存控制的使用 --> 传送门

终止函数 Terminate

所谓终止,其实是 Laravel 运行生命周期结束前的最后处理。处理什么呢?

  • 一是 所有中间件 结尾处理,当然中间件必须有 terminate 方法才行。

    例如:StartSession 这个中间件。

    public function terminate($request, $response)
    {
    if ($this->sessionHandled && $this->sessionConfigured() && ! $this->usingCookieSessions()) {

    // 调用 Session 的 save 方法,向 Laravel 的 storage 中写 session 会话数据
    $this->manager->driver()->save();
    }
    }

    save 方法

    public function save()
    {
    $this->ageFlashData();

    // 序列化当前会话,并保存到 Laravel storage 中。。
    $this->handler->write($this->getId(), $this->prepareForStorage(
    serialize($this->attributes)
    ));

    $this->started = false;
    }
  • 容器终止

    public function terminate()
    {
    // 将终止属性数组中的所有终止闭包函数执行掉。。
    foreach ($this->terminatingCallbacks as $terminating) {
    $this->call($terminating);
    }
    }
    /**
    * 当前方法,就是容器终止属性数组添加终止闭包函数的地方,这里请根据我们项目需要进行调用
    */
    public function terminating(Closure $callback)
    {
    $this->terminatingCallbacks[] = $callback;

    return $this;
    }

  • 最后说一下

完结!!撒花!!!

完结!!撒花!!!

完结!!撒花!!!