我们都知道随着技术的迅速发展,如果不偶尔停下脚步环顾四周,将会错过很多。
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-HTTP2ServerPush
https://github.com/tomschlick/laravel-http2-server-push