菜单

HTTP2 Server Push的研究

2019年4月21日 - 计算机教程

HTTP2 Server Push的研究

2017/01/05 · 基础技术 ·
HTTP/2

原文出处:
AlloyTeam   

本文首发地址为-iOS HTTP/2 Server Push 探索 |
李剑飞的博客

1,HTTP2的新特性。

关于HTTP2的新特性,读着可以参看我之前的文章,这里就不在多说了,本篇文章主要讲一下server
push这个特性。

HTTP,HTTP2.0,SPDY,HTTPS你应该知道的一些事

 


2,Server Push是什么。

简单来讲就是当用户的浏览器和服务器在建立链接后,服务器主动将一些资源推送给浏览器并缓存起来,这样当浏览器接下来请求这些资源时就直接从缓存中读取,不会在从服务器上拉了,提升了速率。举一个例子就是:

假如一个页面有3个资源文件index.html,index.css,index.js,当浏览器请求index.html的时候,服务器不仅返回index.html的内容,同时将index.css和index.js的内容push给浏览器,当浏览器下次请求这2两个文件时就可以直接从缓存中读取了。

图片 1

3,Server Push原理是什么。

要想了解server
push原理,首先要理解一些概念。我们知道HTTP2传输的格式并不像HTTP1使用文本来传输,而是启用了二进制帧(Frames)格式来传输,和server
push相关的帧主要分成这几种类型:

  1. HEADERS
    frame(请求返回头帧):这种帧主要携带的http请求头信息,和HTTP1的header类似。
  2. DATA frames(数据帧) :这种帧存放真正的数据content,用来传输。
  3. PUSH_PROMISE
    frame(推送帧):这种帧是由server端发送给client的帧,用来表示server
    push的帧,这种帧是实现server push的主要帧类型。
  4. RST_STREAM(取消推送帧):这种帧表示请求关闭帧,简单讲就是当client不想接受某些资源或者接受timeout时会向发送方发送此帧,和PUSH_PROMISE
    frame一起使用时表示拒绝或者关闭server push。

Note:HTTP2.0相关的帧其实包括10种帧,正是因为底层数据格式的改变,才为HTTP2.0带来许多的特性,帧的引入不仅有利于压缩数据,也有利于数据的安全性和可靠传输性。

了解了相关的帧类型,下面就是具体server push的实现过程了:

  1. 由多路复用我们可以知道HTTP2中对于同一个域名的请求会使用一条tcp链接而用不同的stream
    ID来区分各自的请求。
  2. 当client使用stream
    1请求index.html时,server正常处理index.html的请求,并可以得知index.html页面还将要会请求index.css和index.js。
  3. server使用stream 1发送PUSH_PROMISE
    frame给client告诉client我这边可以使用stream 2来推送index.js和stream
    3来推送index.css资源。
  4. server使用stream 1正常的发送HEADERS frame和DATA
    frames将index.html的内容返回给client。
  5. client接收到PUSH_PROMISE frame得知stream 2和stream
    3来接收推送资源。
  6. server拿到index.css和index.js便会发送HEADERS frame和DATA
    frames将资源发送给client。
  7. client拿到push的资源后会缓存起来当请求这个资源时会从直接从从缓存中读取。

下图表示了整个流程:

图片 2

HTTP/2

4,Server Push怎么用。

既然server
push这么神奇,那么我们如何使用呢?怎么设置服务器push哪些文件呢?

首先并不是所有的服务器都支持server
push,nginx目前还不支持这个特性,可以在nginx的官方博客上得到证实https://www.nginx.com/blog/http2-r7/,但是Apache和nodejs都已经支持了server
push这一个特性,需要说明一点的是server
push这个特性是基于浏览器和服务器的,所以浏览器并没有提供相应的js
api来让用户直接操作和控制push的内容,所以只能是通过header信息和server的配置来实现具体的push内容,本文主要以nodejs来说明具体如何使用server
push这一特性。

准备工作:下载nodejs
http2
支持,本地启动nodejs服务。

1. 首先我们使用nodejs搭建基本的server:

JavaScript

var http2 = require(‘http2’);   var url=require(‘url’); var
fs=require(‘fs’); var mine=require(‘./mine’).types; var
path=require(‘path’);   var server = http2.createServer({   key:
fs.readFileSync(‘./zs/localhost.key’),   cert:
fs.readFileSync(‘./zs/localhost.crt’) }, function(request, response) {
    var pathname = url.parse(request.url).pathname;     var realPath =
path.join(“my”, pathname);    //这里设置自己的文件名称;       var
pushArray = [];     var ext = path.extname(realPath);     ext = ext ?
ext.slice(1) : ‘unknown’;     var contentType = mine[ext] ||
“text/plain”;       if (fs.existsSync(realPath)) {  
        response.writeHead(200, {             ‘Content-Type’:
contentType         });  
        response.write(fs.readFileSync(realPath,’binary’));       } else
{       response.writeHead(404, {           ‘Content-Type’: ‘text/plain’
      });         response.write(“This request URL ” + pathname + ” was
not found on this server.”);       response.end();     }   });  
server.listen(443, function() {   console.log(‘listen on 443’); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
var http2 = require(‘http2’);
 
var url=require(‘url’);
var fs=require(‘fs’);
var mine=require(‘./mine’).types;
var path=require(‘path’);
 
var server = http2.createServer({
  key: fs.readFileSync(‘./zs/localhost.key’),
  cert: fs.readFileSync(‘./zs/localhost.crt’)
}, function(request, response) {
    var pathname = url.parse(request.url).pathname;
    var realPath = path.join("my", pathname);    //这里设置自己的文件名称;
 
    var pushArray = [];
    var ext = path.extname(realPath);
    ext = ext ? ext.slice(1) : ‘unknown’;
    var contentType = mine[ext] || "text/plain";
 
    if (fs.existsSync(realPath)) {
 
        response.writeHead(200, {
            ‘Content-Type’: contentType
        });
 
        response.write(fs.readFileSync(realPath,’binary’));
 
    } else {
      response.writeHead(404, {
          ‘Content-Type’: ‘text/plain’
      });
 
      response.write("This request URL " + pathname + " was not found on this server.");
      response.end();
    }
 
});
 
server.listen(443, function() {
  console.log(‘listen on 443’);
});

这几行代码就是简单搭建一个nodejs
http2服务,打开chrome,我们可以看到所有请求都走了http2,同时也可以验证多路复用的特性。

图片 3

这里需要注意几点:

  1. 创建http2的nodejs服务必须时基于https的,因为现在主流的浏览器都要支持SSL/TLS的http2,证书和私钥可以自己通过OPENSSL生成。
  2. node http2的相关api和正常的node httpserver相同,可以直接使用。

  3. 设置我们的server push:

JavaScript

var pushItem = response.push(‘/css/bootstrap.min.css’, {        request:
{             accept: ‘*/\*’        },       response: {
            ‘content-type’: ‘text/css’      } });
pushItem.end(fs.readFileSync(‘/css/bootstrap.min.css’,’binary’));

1
2
3
4
5
6
7
8
9
var pushItem = response.push(‘/css/bootstrap.min.css’, {
       request: {
            accept: ‘*/\*’
       },
      response: {
            ‘content-type’: ‘text/css’
     }
});
pushItem.end(fs.readFileSync(‘/css/bootstrap.min.css’,’binary’));

我们设置了bootstrap.min.css来通过server
push到我们的浏览器,我们可以在浏览器中查看:

图片 4

可以看到,启动server push的资源timelime非常快,大大加速了css的获取时间。

这里需要注意下面几点:

  1. 我们调用response.push(),就是相当于server发起了PUSH_PROMISE
    frame来告知浏览器bootstrap.min.css将会由server push来获取。
  2. response.push()返回的对象时一个正常的ServerResponse,end(),writeHeader()等方法都可以正常调用。
  3. 这里一旦针对某个资源调用response.push()即发起PUSH_PROMISE
    frame后,要做好容错机制,因为浏览器在下次请求这个资源时会且只会等待这个server
    push回来的资源,这里要做好超时和容错即下面的代码:
  4. JavaScript

    try {
        pushItem.end(fs.readFileSync(‘my/css/bootstrap.min.css’,’binary’));
        } catch(e) {        response.writeHead(404, {           
    ‘Content-Type’: ‘text/plain’        });        response.end(‘request
    error’); }   pushItem.stream.on(‘error’, function(err){
        response.end(err.message); });   pushItem.stream.on(‘finish’,
    function(err){    console.log(‘finish’); });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    try {
        pushItem.end(fs.readFileSync(‘my/css/bootstrap.min.css’,’binary’));
        } catch(e) {
           response.writeHead(404, {
               ‘Content-Type’: ‘text/plain’
           });
           response.end(‘request error’);
    }
     
    pushItem.stream.on(‘error’, function(err){
        response.end(err.message);
    });
     
    pushItem.stream.on(‘finish’, function(err){
       console.log(‘finish’);
    });

    上面的代码你可能会发现许多和正常nodejs的httpserver不一样的东西,那就是stream,其实整个http2都是以stream为单位,这里的stream其实可以理解成一个请求,更多的api可以参考:node-http2

  5. 最后给大家推荐一个老外写的专门服务http2的node
    server有兴趣的可以尝试一下。https://gitlab.com/sebdeckers/http2server

HTTP/2 Server Push 是什么

当用户的浏览器和服务器在建立链接后,服务器主动将一些资源推送给浏览器并缓存起来,这样当浏览器接下来请求这些资源时就直接从缓存中读取,不会在从服务器上拉了,提升了速率。举一个例子就是:

假如一个页面有3个资源文件index.html,index.css,index.js,当浏览器请求index.html的时候,服务器不仅返回index.html的内容,同时将index.css和index.js的内容push给浏览器,当浏览器下次请求这2两个文件时就可以直接从缓存中读取了。

如下图所示:

图片 5

Apple-http2ServerPush

5,Server Push相关问题。

  1. 我们知道现在我们web的资源一般都是放在CDN上的,那么CDN的优势和server
    push的优势有何区别呢,到底是哪个比较快呢?这个问题笔者也一直在研究,本文的相关demo都只能算做一个演示,具体的线上实践还在进行中。
  2. 由于HTTP2的一些新特性例如多路复用,server
    push等等都是基于同一个域名的,所以这可能会对我们之前对于HTTP1的一些优化措施例如(资源拆分域名,合并等等)不一定适用。
  3. server
    push不仅可以用作拉取静态资源,我们的cgi请求即ajax请求同样可以使用server
    push来发送数据。
  4. 最完美的结果是CDN域名支持HTTP2,web server域名也同时支持HTTP2。

 

参考资料:

  1. HTTP2官方标准:https://tools.ietf.org/html/rfc7540
  2. 维基百科:https://en.wikipedia.org/wiki/HTTP/2_Server_Push
  3. https://www.nihaoshijie.com.cn/index.php/archives/651

    1 赞 1 收藏
    评论

图片 6

HTTP/2 Server Push 原理是什么

要想了解server
push原理,首先要理解一些概念。我们知道HTTP/2传输的格式并不像HTTP1使用文本来传输,而是启用了二进制帧(Frames)格式来传输,和server
push相关的帧主要分成这几种类型:

  1. HEADERS
    frame(请求返回头帧):这种帧主要携带的http请求头信息,和HTTP1的header类似。
  2. DATA frames(数据帧) :这种帧存放真正的数据content,用来传输。
  3. PUSH_PROMISE
    frame(推送帧):这种帧是由server端发送给client的帧,用来表示server
    push的帧,这种帧是实现server push的主要帧类型。
  4. RST_STREAM(取消推送帧):这种帧表示请求关闭帧,简单讲就是当client不想接受某些资源或者接受timeout时会向发送方发送此帧,和PUSH_PROMISE
    frame一起使用时表示拒绝或者关闭server push。

(PS:HTTP/2相关的帧其实包括10种帧,正是因为底层数据格式的改变,才为HTTP/2带来许多的特性,帧的引入不仅有利于压缩数据,也有利于数据的安全性和可靠传输性。)

了解了相关的帧类型,下面就是具体server push的实现过程了:

  1. 由多路复用我们可以知道HTTP/2中对于同一个域名的请求会使用一条tcp链接而用不同的stream
    ID来区分各自的请求。
  2. 当client使用stream
    1请求index.html时,server正常处理index.html的请求,并可以得知index.html页面还将要会请求index.css和index.js。
  3. server使用stream 1发送PUSH_PROMISE
    frame给client告诉client我这边可以使用stream 2来推送index.js和stream
    3来推送index.css资源。
  4. server使用stream 1正常的发送HEADERS frame和DATA
    frames将index.html的内容返回给client。
  5. client接收到PUSH_PROMISE frame得知stream 2和stream
    3来接收推送资源。
  6. server拿到index.css和index.js便会发送HEADERS frame和DATA
    frames将资源发送给client。
  7. client拿到push的资源后会缓存起来当请求这个资源时会从直接从从缓存中读取。

Server Push 怎么用

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图