基于 Laravel 中间件简单地整合 HTTP/2 服务器资源推送


我们都知道随着技术的迅速发展,如果不偶尔停下脚步环顾四周,将会错过很多。

HTTP/2 ,很热的一个技术话题。实话说, Ben Ramsey 在 laracon 对此发表演讲之前,我对其一无所知。而本文将介绍 HTTP/2 众多理念中的一个——服务器资源推送。

读者想要了解更多,可观看视频或者访问他的网站。了解后,你会发现实现服务器推送、预加载资源数据简单地让人大吃一惊。基本上,只要在服务器端响应的头部添加一个带有整个页面资源的特殊“ link ”,如果服务器和浏览器都支持的话,这些资源将以高效的网络方式拉取获得(具体点击链接 )。

在 Ben 的演讲中,他举了如何在 laravel 中实现的例子,这是其中一种方法。

  return response($content, $status)
  ->header('Link', '; rel=preload; as=style', false)
  ->header('Link', '; rel=preload; as=script', false);

当然,如果这样一个一个资源实现推送是件可怕的事情。但是,感谢活跃的 laravel 用户,目前已经有两个基于 laravel 中间件自动整合资源实现统一推送的包了。

其中一个是 Tome Schlick 创建的,另一个是 Jacob Bennett。大体上,这两个包没什么区别,但是在如何整合资源方面两个作者都有各自的想法。

Tome

*实现

先在 config/server-push.php 中,手动定义默认的资源文件包括 style、script、image 等。同时,并配置是否从 mianfest 中自动导入资源数据。

return [
    // Include assets you want to link on every page load here.
    'default_links' => [
        'styles' => [
        ],
        'scripts' => [
        ],
        'images' => [
        ],
    ],

    'autolink_from_manifest' => true,

    'manifest_path'   => public_path('build/rev-manifest.json')
];

中间件—— Http2ServerPushMiddleware.php 先验证请求是否为页面请求,若为页面请求,则将拼接成的“link“添加到响应的头部中。

   public function handle(Request $request, Closure $next)
    {
        $this->response = $next($request);
        if ($this->shouldUseServerPush($request)) {
            $this->addServerPushHeaders();
        }
        return $this->response;
    }

    protected function addServerPushHeaders()
    {
        if (app('server-push')->hasLinks()) {
            $link = implode(',', app('server-push')->generateLinks());
            $this->response->headers->set('Link', $link, false);
        }
    }

    protected function shouldUseServerPush(Request $request) : bool
    {
        return !$request->ajax();
    }

到这里,你可能会想那配置文件中的那些数据用处在哪呢?
哈哈,接下来 ServiceProvider 便会用到了,下列方法中先添加手动填写的默认资源链接,接着添加 mainfest 中的资源数据。具体实现请看详细代码,这里就不多阐述了。

public function register()
{
        $this->app->singleton('server-push', function () {
            return new HttpPush();
        });
        $this->app->alias('server-push', HttpPush::class);
        $this->registerDefaultLinks();
        $this->registerElixirLinks();
}
  • 安装

秉着实用主义的心理,安装使用才是最重要的了!

composer 安装:

composer require tomschlick/laravel-http2-server-push

config/app.php 中注册 provider:

\TomSchlick\ServerPush\ServiceProvider::class,

app/Http/kernel.php中注册中间件:

protected $middleware = [
    \TomSchlick\ServerPush\Http2ServerPushMiddleware::class,
];

注意,你还可以在项目中任何地方使用下列方法根据具体情况添加局部的资源文件,很方便有没有。

 pushStyle($pathOfCssFile);
 pushScript($pathOfJsFile);
 pushImage($pathOfImageFile);

Jacob

  • 实现

相比之下,这个包较为简练,所有的逻辑全部都在中间件中处理。

将需要推送资源的路由加上中间件—— AddHttp2ServerPush ,中间件将会自动那些需要服务器来推送的 css,style,image 等资源并将它们加到服务器响应的头部。

public function handle(Request $request, Closure $next, $limit = null)
    {
        $response = $next($request);
        if ($response->isRedirection() || !$response instanceof Response || $request->isJson()) {
            return $response;
        }
        $this->generateAndAttachLinkHeaders($response, $limit);
        return $response;
    }

上述是部分中间件代码。首先可以看出这是一个后置中间件。然后流程这样走:校验服务器响应和浏览器请求,若非跳转响应并请求非发送 Json 数据——>获取服务器响应想要推送的资源——>基于资源里的文件名后缀即文件类型组合生成头部字符串——>添加到响应的头部中。

  • 安装

composer 安装:

 $ composer require jacobbennett/laravel-http2serverpush

千万不要忘记把中间件添加
\JacobBennett\Http2ServerPush\Middleware\AddHttp2ServerPush
app/Http/Kernel.php 中!可直接放到 web 组中,一劳永逸。也可根据具体需求添加到个别路由中。

protected $middlewareGroups = [
    'web' => [
        ...
        \JacobBennett\Http2ServerPush\Middleware\AddHttp2ServerPush::class,
        ...
    ],
    ...
];

讲了这么多,选用哪个包还是依据具体项目和个人偏好来决定。Jacob 的包必须扫描所有的视图来获取全部资源。相比之下,Tome 的包需要手动操作,但是使用者能够更方便地控制。

实践是检验真理的唯一标准,为了提高 laravel 应用性能,不要犹豫来,动手试试看吧!

参考链接:https://laravel-news.com/http2-server-push-middleware\JacobBennett\Http2ServerPush\Middleware\AddHttp2ServerPush
https://github.com/JacobBennett/laravel-HT...
https://github.com/tomschlick/laravel-http...

本作品采用《CC 协议》,转载必须注明作者和本文链接
step by step
本帖由 Summer 于 6年前 加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 6
Summer

加油 ?

6年前 评论

@Summer 哈哈哈,好的。还请多多指教~:smile:

6年前 评论

中间件是个好东西!

6年前 评论

然而如果静态资源全部走 CDN 是不是主动资源推送就没什么用了?

6年前 评论

@HyanCat 嗯呢,是的。我看知乎上一个多月前发的文章写到目前国内的cdn普遍还不支持http/2的服务器推送。https://zhuanlan.zhihu.com/p/26757514

6年前 评论

又拍云 CDN 在 HTTPS 协议的基础上早已实现全平台支持 HTTP/2。有兴趣的可以看下这篇文章。《一文读懂 HTTP/2 特性》

6年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!