终章 --- 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;
    }

  • 最后说一下

完结!!撒花!!!

完结!!撒花!!!

完结!!撒花!!!

本篇如有错误、不当或者需补充的内容,请各位同僚多提宝贵意见。

本文章首发在 LearnKu.com 网站上。
上一篇 下一篇
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 0
发起讨论 只看当前版本


暂无话题~