使用 Symfony 组件创建自己的 PHP 框架(第十部分:HttpKernelInterface 组件与页面缓存)

使用 Symfony 组件创建自己的 PHP 框架(第十部分:HttpKernelInterface 组件与页面缓存)

Chris Yue One comment
Posts

英文原文地址:https://symfony.com/doc/current/create_framework/http_kernel_httpkernelinterface.html

我曾在第二章的结论里谈到过,使用 Symfony 组件库的好处之一是:让所有使用他们的的框架或者应用程序都有很好的互用性(interoperability, 译者注:这个单词并不知道准确的对应的中文。举一个例子,如果电视机插头按照国内标准的两线插头去生产,那么国内所有的两线插座都可以给这台电视机供电,这就是 interoperability,简单说,就是一种让各种不同的模块或者系统在一起工作的能力)。为了向此目标再迈出一大步,我们得让框架实现 HttpKernelInterface 这个接口:

namespace Symfony\Component\HttpKernel;

interface HttpKernelInterface
{
    /**
     * @return Response A Response instance
     */
    function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true);
}

HttpKernelInterface 算是 HttpKernel 组件里面最重要的代码了,真的。实现了此接口的框架或者应用程序会立马具有互操作性,并且随之会带来更多的好处

更新你的框架代码,让他实现 HttpKernelInterface 接口

<?php

// example.com/src/Framework.php

// ...

use Symfony\Component\HttpKernel\HttpKernelInterface;

class Framework implements HttpKernelInterface
{
    // ...

    public function handle(
        Request $request, 
        $type = HttpKernelInterface::MASTER_REQUEST, 
        $catch = true
    ) {
        // ...
    }
}

虽然看起来这是一个微不足道的改动,但其实此改动给我们带来了很多特性。首当其冲便是令人形象深刻的 HTTP 缓存功能。

HttpCache是使用 php 实现的,一个功能完整的反向代理。它也实现了HttpKernelInterface 并可以将另外一个用 HttpKernelInterface 实现的类包起来:

use Symfony\Component\HttpKernel\HttpCache\HttpCache;
use Symfony\Component\HttpKernel\HttpCache\Store;

$framework = new Simplex\Framework($dispatcher, $matcher, $resolver);
$framework = new HttpCache($framework, new Store(__DIR__.'/../cache'));

$framework->handle($request)->send();

这便是我们要为我们的框架添加 HTTP 缓存功能的所有代码,是不是很给力?

我们需要通过改变相应头来对缓存策略进行配置。比如要将一个页面缓存 10 秒,我们需要调用 Response::setTtl方法

// example.com/src/Calendar/Controller/LeapYearController.php

public function indexAction(Request $request, $year)
{
    $leapyear = new LeapYear();
    if ($leapyear->isLeapYear($year)) {
        $response = new Response('Yep, this is a leap year!');
    } else {
        $response = new Response('Nope, this is not a leap year.');
    }

    $response->setTtl(10);

    return $response;
}

如果你跟我一样,喜欢在命令行下面模拟请求来调试代码,你可以轻而易举的使用 echo $response; 的方式将所有的响应头信息以及内容全部显示出来(译者注:如果入口文件是 front.php,你可以用类似 Request::create('/is_leap_year/2012') 的方式模拟一个请求,然后在框架处理了这个请求并返回了响应对象之后,不直接调用响应的 send 方法,而是直接 echo 出这个响应对象,你就可以通过命令行下执行 php front.php 来查看 response 的详细信息)

让我们写个随机数来验证我们的缓存功能是否好用:

$response = new Response('Yep, this is a leap year! '.rand());

在你部署代码到投产机的时候,记得使用 Symfony 的反向代理来提升性能,或者用更加专业的反相代理软件 Varnish

利用 HTTP 头信息来管理缓存很好很强大,它既可以使用过期策略,也可以使用验证策略来管理你的缓存。如果你对这些概念不熟悉话,最好先阅读一下 Symfony 文档的 HTTP 缓存部分

Response 类包含了很多方法来让你方便管理 HTTP 缓存,setCache 方法便是其中最强大的方法之一,它可以通过一个数组来设定所有的缓存参数:

$date = date_create_from_format('Y-m-d H:i:s', '2005-10-15 10:00:00');

$response->setCache(array(
    'public'        => true,
    'etag'          => 'abcde',
    'last_modified' => $date,
    'max_age'       => 10,
    's_maxage'      => 10,
));

// 等同于以下代码
$response->setPublic();
$response->setEtag('abcde');
$response->setLastModified($date);
$response->setMaxAge(10);
$response->setSharedMaxAge(10);

在验证模式下,你可以通过 isNotModified 方法来判断是否可将响应缓存直接返回,从而节省响应时间。

$response->setETag('whatever_you_compute_as_an_etag');

if ($response->isNotModified($request)) {
    return $response;
}

$response->setContent('The computed content of the response');

return $response;

虽然 HTTP 缓存很给力,但万一你不能缓存整个页面而只是一部分怎么办?比如说页头用户信息?没事,ESI(Edge Side Includes)来帮您!它可以用『子请求』的方式生成页面部分缓存,来代替整个页面的缓存。

This is the content of your page

Is 2012 a leap year? <esi:include src="/leapyear/2012" />

Some other content

你需要在 HttpCache 对象里传入 ESI 对象,来开启 HttpCache 类对 ESI 功能的支持,设置以后 HttpCache 便可以自动识别 ESI 标签并生成一个子请求。

use Symfony\Component\HttpKernel\HttpCache\ESI;

$framework = new HttpCache($framework, new Store(__DIR__.'/../cache'), new ESI());

要让 ESI 正常工作,你需要一个支持 ESI 的反向代理,比如 Symfony 的实现,或者使用 Varnish

如果设置了太多的缓存机制,或者太多的 ESI 标签,你可能非常难看得出那些应该缓存而那些不应该,这个时候你可以将 debug 设置打开进行调试:

$framework = new HttpCache(
    $framework, 
    new Store(__DIR__.'/../cache'), 
    new ESI(), 
    array('debug' => true)
);

调试器将会在头信息中加入 X-Symfony-Cache 信息来表述缓存层都做了些什么:

X-Symfony-Cache:  GET /is_leap_year/2012: stale, invalid, store

X-Symfony-Cache:  GET /is_leap_year/2012: fresh

HttpCache 实现了很多功能比如 stale-while-revalidatestale-if-error 等 RFC 5861 协议中定义的 Http Cache-Control 的扩展功能

在一个简单的接口的帮助下,我们的框架可以享受 HttpKernel 组件的许多功能。HTTP 缓存只是其中的一个重要部分,但已经能让你的框架运行如飞了!

返回阅读第九部分 | 继续阅读第十一部分

使用 Symfony 组件创建自己的 PHP 框架(第十部分:HttpKernelInterface 组件与页面缓存) by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

微信赞赏码

写作累,服务器还越来越贵
求分担,祝愿好人一生平安
天使打赏人

One comment

wg

一月 3, 2017 在 4:07 下午

interoperability 可以翻译为“互操作性”

发表评论

− 2 = 6