美高梅网投网站-美高梅手机网投-美高梅官方网站
做最好的网站

您的位置:美高梅网投网址 > Web前端 > 美高梅官方网站原稿出处,李剑飞的博客

美高梅官方网站原稿出处,李剑飞的博客

发布时间:2019-09-27 05:21编辑:Web前端浏览(154)

    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. HEADESportageS 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. 由多路复用大家能够清楚HTTP第22中学对于同一个域名的央求会利用一条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符合规律的发送HEADECRUISERS frame和DATA frames将index.html的内容重返给client。
    5. client接收到PUSH_PROMISE frame得知stream 2和stream 3来接受推送财富。
    6. server获得index.css和index.js便会发送HEADE奥迪Q3S frame和DATA frames将能源发送给client。
    7. client获得push的财富后会缓存起来当呼吁这么些能源时会从第一手从从缓存中读取。

    下图表示了整整流程:

    美高梅官方网站 2

    HTTP/2

    4,Server Push怎么用。

    既然server push这么神奇,那么我们什么样行使啊?怎么设置服务器push哪些文件呢?

    先是并不是富有的服务器都协理server push,nginx方今还不协理那么些脾性,可以在nginx的合法博客上获得表明,然而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 real帕特h = 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有兴趣的能够品味一下。

    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官方正式:
    2. 维基百科:
    3. 1 赞 1 收藏 评论

    美高梅官方网站 6

    HTTP/2 Server Push 原理是如何

    要想精通server push原理,首先要知道一些概念。我们明白HTTP/2传输的格式并不像HTTP1使用文本来传输,而是启用了二进制帧(Frames)格式来传输,和server push相关的帧重要分为这二种档案的次序:

    1. HEADELacrosseS 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不奇怪的出殡HEADEENCORES frame和DATA frames将index.html的剧情再次回到给client。
    5. client接收到PUSH_PROMISE frame得知stream 2和stream 3来接受推送财富。
    6. server获得index.css和index.js便会发送HEADE哈弗S frame和DATA frames将财富发送给client。
    7. client获得push的财富后会缓存起来当呼吁那几个资源时会从一贯从从缓存中读取。

    Server Push 怎么用

    使用 nghttp2 调试 HTTP/2 流量

    翻看 HTTP/2 流量的几种方法

    • 在 Chrome 地址栏输入 chrome://net-internals/#http2,使用 Chrome 自带的 HTTP/2 调节和测验工具;
      使用方便,但受限于 Chrome 浏览器,对于 Chrome 不帮助的 h2c(HTTP/2 Cleartext,未有安插 TLS 的 HTTP/2)协议不可能。同有时间,这么些工具展现的音信经过了分析和筛选,相当不够完美。
    • 使用 Wireshark 调试 HTTP/2 流量;
      Wireshark 位于服务端和浏览器之间,充当的是中间人剧中人物,用它查看 HTTP/2 over HTTPS 流量时,必得怀有网址私钥或许借助浏览器分享对称密钥,技巧解密 TLS 流量,配置起来比较艰苦。

    nghttp2,是贰个用 C 完结的 HTTP/2 库,帮衬h2c。它可以做为另外软件的一局部,为其提供 HTTP/2 相关职能(例如 curl 的 HTTP/2 功用正是用的 nghttp2)。除外,它还提供了多少个有效的 HTTP/2 工具:

    • nghttp:HTTP/2 客户端;
    • nghttpd:HTTP/2 服务端;
    • nghttpx:HTTP/2 代理,提供 HTTP/1、HTTP/2 等协议时期的转移;
    • h2load:HTTP/2 品质测验工具;

    nghttp2 安装

    先来用 brew 看一下有未有 nghttp 相关的库:

    ~ brew search nghttp
    nghttp2
    

    由此看来是有 nghttp2 的,再用 brew 看下要求设置哪些条件:

    ~ brew info nghttp2
    nghttp2: stable 1.21.0 (bottled), HEAD
    HTTP/2 C Library
    https://nghttp2.org/
    Not installed
    From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/nghttp2.rb
    ==> Dependencies
    Build: sphinx-doc ✘, pkg-config ✔, cunit ✘
    Required: c-ares ✘, libev ✘, openssl ✔, libevent ✘, jansson ✘, boost ✘, spdylay ✘
    Recommended: jemalloc ✘
    ==> Requirements
    Optional: python3 ✔
    ==> Options
    --with-examples
        Compile and install example programs
    --with-python3
        Build python3 bindings
    --without-docs
        Don't build man pages
    --without-jemalloc
        Build without jemalloc support
    --HEAD
        Install HEAD version
    

    由此看来要求的借助还挺多。

    使用 brew 安装 nghttp2 :

    brew install nghttp2
    

    一切妥当后,nghttp2 提供的多少个工具就能够直接用了。

    nghttp

    nghttp 做为多少个效果一体化的 HTTP/2 客商端,非常符合用来查阅和调节和测量检验 HTTP/2 流量。它帮助的参数非常多,通过法定文书档案大概 nghttp -h 都能查看。最常用多少个参数如下:

    • -v, --verbose,输出完整的 debug 新闻;
    • -n, --null-out,吐弃下载的数目;
    • -a, --get-assets,下载 html 中的 css、js、image 等外链财富;
    • -H, --header = < HEADE奥迪Q7 >,加多需要尾部字段,如 -H':method: PUT';
    • -u, --upgrade,使用 HTTP 的 Upgrade 机制来切磋 HTTP/2 合同,用于 h2c,详见下边包车型大巴事例;

    以下是运用 nghttp 访问 https://h2o.examp1e.net 的结果。从调节和测量检验消息中得以清楚看出 h2c 协商以及 Server Push 的全方位经过:

    nghttp -nv 'https://h2o.examp1e.net'
    [  0.201] Connected
    The negotiated protocol: h2
    [  1.180] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
              (niv=2)
              [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
              [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
    [  1.180] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
              (dep_stream_id=0, weight=201, exclusive=0)
    [  1.180] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
              (dep_stream_id=0, weight=101, exclusive=0)
    [  1.180] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
              (dep_stream_id=0, weight=1, exclusive=0)
    [  1.180] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
              (dep_stream_id=7, weight=1, exclusive=0)
    [  1.180] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
              (dep_stream_id=3, weight=1, exclusive=0)
    [  1.180] send HEADERS frame <length=39, flags=0x25, stream_id=13>
              ; END_STREAM | END_HEADERS | PRIORITY
              (padlen=0, dep_stream_id=11, weight=16, exclusive=0)
              ; Open new stream
              :method: GET
              :path: /
              :scheme: https
              :authority: h2o.examp1e.net
              accept: */*
              accept-encoding: gzip, deflate
              user-agent: nghttp2/1.21.1
    [  1.373] recv SETTINGS frame <length=12, flags=0x00, stream_id=0>
              (niv=2)
              [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
              [SETTINGS_INITIAL_WINDOW_SIZE(0x04):16777216]
    [  1.373] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
              ; ACK
              (niv=0)
    [  1.373] recv (stream_id=13) :method: GET
    [  1.373] recv (stream_id=13) :scheme: https
    [  1.373] recv (stream_id=13) :authority: h2o.examp1e.net
    [  1.373] recv (stream_id=13) :path: /search/jquery-1.9.1.min.js
    [  1.373] recv (stream_id=13) accept: */*
    [  1.373] recv (stream_id=13) accept-encoding: gzip, deflate
    [  1.373] recv (stream_id=13) user-agent: nghttp2/1.21.1
    [  1.373] recv PUSH_PROMISE frame <length=59, flags=0x04, stream_id=13>
              ; END_HEADERS
              (padlen=0, promised_stream_id=2)
    [  1.373] recv (stream_id=2) :status: 200
    [  1.373] recv (stream_id=2) server: h2o/2.2.0-beta2
    [  1.373] recv (stream_id=2) date: Mon, 10 Apr 2017 06:30:29 GMT
    [  1.373] recv (stream_id=2) content-type: application/javascript
    [  1.373] recv (stream_id=2) last-modified: Thu, 14 May 2015 04:10:14 GMT
    [  1.373] recv (stream_id=2) etag: "55542026-169d5"
    [  1.373] recv (stream_id=2) accept-ranges: bytes
    [  1.373] recv (stream_id=2) x-http2-push: pushed
    [  1.373] recv (stream_id=2) content-length: 92629
    [  1.373] recv HEADERS frame <length=126, flags=0x04, stream_id=2>
              ; END_HEADERS
              (padlen=0)
              ; First push response header
    [  1.373] recv (stream_id=13) :method: GET
    [  1.373] recv (stream_id=13) :scheme: https
    [  1.373] recv (stream_id=13) :authority: h2o.examp1e.net
    [  1.373] recv (stream_id=13) :path: /search/oktavia-jquery-ui.js
    [  1.373] recv (stream_id=13) accept: */*
    [  1.373] recv (stream_id=13) accept-encoding: gzip, deflate
    [  1.373] recv (stream_id=13) user-agent: nghttp2/1.21.1
    [  1.373] recv PUSH_PROMISE frame <length=33, flags=0x04, stream_id=13>
              ; END_HEADERS
              (padlen=0, promised_stream_id=4)
    [  1.373] recv (stream_id=4) :status: 200
    [  1.373] recv (stream_id=4) server: h2o/2.2.0-beta2
    [  1.373] recv (stream_id=4) date: Mon, 10 Apr 2017 06:30:29 GMT
    [  1.373] recv (stream_id=4) content-type: application/javascript
    [  1.373] recv (stream_id=4) last-modified: Thu, 14 May 2015 04:10:14 GMT
    [  1.373] recv (stream_id=4) etag: "55542026-1388"
    [  1.373] recv (stream_id=4) accept-ranges: bytes
    [  1.374] recv (stream_id=4) x-http2-push: pushed
    [  1.374] recv (stream_id=4) content-length: 5000
    [  1.374] recv HEADERS frame <length=28, flags=0x04, stream_id=4>
              ; END_HEADERS
              (padlen=0)
              ; First push response header
    [  1.374] recv (stream_id=13) :method: GET
    [  1.374] recv (stream_id=13) :scheme: https
    [  1.374] recv (stream_id=13) :authority: h2o.examp1e.net
    [  1.374] recv (stream_id=13) :path: /search/oktavia-english-search.js
    [  1.374] recv (stream_id=13) accept: */*
    [  1.374] recv (stream_id=13) accept-encoding: gzip, deflate
    [  1.374] recv (stream_id=13) user-agent: nghttp2/1.21.1
    [  1.374] recv PUSH_PROMISE frame <length=35, flags=0x04, stream_id=13>
              ; END_HEADERS
              (padlen=0, promised_stream_id=6)
    [  1.374] recv (stream_id=6) :status: 200
    [  1.374] recv (stream_id=6) server: h2o/2.2.0-beta2
    [  1.374] recv (stream_id=6) date: Mon, 10 Apr 2017 06:30:29 GMT
    [  1.374] recv (stream_id=6) content-type: application/javascript
    [  1.374] recv (stream_id=6) last-modified: Thu, 14 May 2015 04:10:14 GMT
    [  1.374] recv (stream_id=6) etag: "55542026-34dd6"
    [  1.374] recv (stream_id=6) accept-ranges: bytes
    [  1.374] recv (stream_id=6) x-http2-push: pushed
    [  1.374] recv (stream_id=6) content-length: 216534
    [  1.374] recv HEADERS frame <length=31, flags=0x04, stream_id=6>
              ; END_HEADERS
              (padlen=0)
              ; First push response header
    [  1.374] recv (stream_id=13) :method: GET
    [  1.374] recv (stream_id=13) :scheme: https
    [  1.374] recv (stream_id=13) :authority: h2o.examp1e.net
    [  1.374] recv (stream_id=13) :path: /assets/style.css
    [  1.374] recv (stream_id=13) accept: */*
    [  1.374] recv (stream_id=13) accept-encoding: gzip, deflate
    [  1.374] recv (stream_id=13) user-agent: nghttp2/1.21.1
    [  1.374] recv PUSH_PROMISE frame <length=24, flags=0x04, stream_id=13>
              ; END_HEADERS
              (padlen=0, promised_stream_id=8)
    [  1.374] recv (stream_id=8) :status: 200
    [  1.374] recv (stream_id=8) server: h2o/2.2.0-beta2
    [  1.374] recv (stream_id=8) date: Mon, 10 Apr 2017 06:30:29 GMT
    [  1.374] recv (stream_id=8) content-type: text/css
    [  1.374] recv (stream_id=8) last-modified: Tue, 20 Sep 2016 05:27:06 GMT
    [  1.374] recv (stream_id=8) etag: "57e0c8aa-1586"
    [  1.374] recv (stream_id=8) accept-ranges: bytes
    [  1.374] recv (stream_id=8) x-http2-push: pushed
    [  1.374] recv (stream_id=8) content-length: 5510
    [  1.374] recv HEADERS frame <length=58, flags=0x04, stream_id=8>
              ; END_HEADERS
              (padlen=0)
              ; First push response header
    [  1.374] recv (stream_id=13) :method: GET
    [  1.374] recv (stream_id=13) :scheme: https
    [  1.374] recv (stream_id=13) :authority: h2o.examp1e.net
    [  1.374] recv (stream_id=13) :path: /assets/searchstyle.css
    [  1.374] recv (stream_id=13) accept: */*
    [  1.374] recv (stream_id=13) accept-encoding: gzip, deflate
    [  1.374] recv (stream_id=13) user-agent: nghttp2/1.21.1
    [  1.374] recv PUSH_PROMISE frame <length=28, flags=0x04, stream_id=13>
              ; END_HEADERS
              (padlen=0, promised_stream_id=10)
    [  1.374] recv (stream_id=10) :status: 200
    [  1.374] recv (stream_id=10) server: h2o/2.2.0-beta2
    [  1.374] recv (stream_id=10) date: Mon, 10 Apr 2017 06:30:29 GMT
    [  1.374] recv (stream_id=10) content-type: text/css
    [  1.374] recv (stream_id=10) last-modified: Tue, 20 Sep 2016 05:27:06 GMT
    [  1.374] recv (stream_id=10) etag: "57e0c8aa-8dd"
    [  1.374] recv (stream_id=10) accept-ranges: bytes
    [  1.374] recv (stream_id=10) x-http2-push: pushed
    [  1.374] recv (stream_id=10) content-length: 2269
    [  1.374] recv HEADERS frame <length=27, flags=0x04, stream_id=10>
              ; END_HEADERS
              (padlen=0)
              ; First push response header
    [  1.374] recv (stream_id=13) :status: 200
    [  1.374] recv (stream_id=13) server: h2o/2.2.0-beta2
    [  1.374] recv (stream_id=13) date: Mon, 10 Apr 2017 06:30:29 GMT
    [  1.374] recv (stream_id=13) link: </search/jquery-1.9.1.min.js>; rel=preload
    [  1.374] recv (stream_id=13) link: </search/oktavia-jquery-ui.js>; rel=preload
    [  1.374] recv (stream_id=13) link: </search/oktavia-english-search.js>; rel=preload
    [  1.374] recv (stream_id=13) link: </assets/style.css>; rel=preload
    [  1.374] recv (stream_id=13) link: </assets/searchstyle.css>; rel=preload
    [  1.374] recv (stream_id=13) cache-control: no-cache
    [  1.374] recv (stream_id=13) content-type: text/html
    [  1.374] recv (stream_id=13) last-modified: Wed, 05 Apr 2017 06:55:14 GMT
    [  1.374] recv (stream_id=13) etag: "58e494d2-1665"
    [  1.374] recv (stream_id=13) accept-ranges: bytes
    [  1.374] recv (stream_id=13) set-cookie: h2o_casper=AmgAAAAAAAAAAAAYxfEYAAABSA; Path=/; Expires=Tue, 01 Jan 2030 00:00:00 GMT; Secure
    [  1.374] recv (stream_id=13) content-length: 5733
    [  1.374] recv HEADERS frame <length=304, flags=0x04, stream_id=13>
              ; END_HEADERS
              (padlen=0)
              ; First response header
    [  1.375] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
              ; ACK
              (niv=0)
    [  1.566] recv DATA frame <length=16137, flags=0x00, stream_id=2>
    [  1.567] recv DATA frame <length=5000, flags=0x01, stream_id=4>
              ; END_STREAM
    [  1.567] recv DATA frame <length=4915, flags=0x00, stream_id=6>
    [  1.766] recv DATA frame <length=2829, flags=0x00, stream_id=8>
    [  1.766] recv DATA frame <length=2269, flags=0x01, stream_id=10>
              ; END_STREAM
    [  1.766] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
              (window_size_increment=33120)
    [  1.767] recv DATA frame <length=9065, flags=0x00, stream_id=2>
    [  1.970] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  1.970] recv DATA frame <length=2681, flags=0x01, stream_id=8>
              ; END_STREAM
    [  1.971] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=2>
              (window_size_increment=33855)
    [  1.971] recv DATA frame <length=10072, flags=0x00, stream_id=2>
    [  2.172] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  2.172] recv DATA frame <length=4248, flags=0x00, stream_id=2>
    [  2.173] recv DATA frame <length=4248, flags=0x00, stream_id=6>
    [  2.173] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
              (window_size_increment=34002)
    [  2.173] recv DATA frame <length=4248, flags=0x00, stream_id=2>
    [  2.577] recv DATA frame <length=4248, flags=0x00, stream_id=6>
    [  2.578] recv DATA frame <length=2829, flags=0x00, stream_id=2>
    [  2.579] recv DATA frame <length=12762, flags=0x00, stream_id=6>
    [  2.777] recv DATA frame <length=2829, flags=0x00, stream_id=2>
    [  2.777] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=6>
              (window_size_increment=33241)
    [  2.778] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  3.177] recv DATA frame <length=8505, flags=0x00, stream_id=2>
    [  3.177] recv DATA frame <length=5667, flags=0x00, stream_id=6>
    [  3.177] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
              (window_size_increment=33993)
    [  3.177] recv DATA frame <length=2829, flags=0x00, stream_id=2>
    [  3.177] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  3.378] recv DATA frame <length=2829, flags=0x00, stream_id=2>
    [  3.579] recv DATA frame <length=11343, flags=0x00, stream_id=6>
    [  3.580] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
              (window_size_increment=34002)
    [  3.580] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=2>
              (window_size_increment=33984)
    [  3.583] recv DATA frame <length=7086, flags=0x00, stream_id=2>
    [  3.779] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  4.186] recv DATA frame <length=7086, flags=0x00, stream_id=2>
    [  4.186] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  4.186] recv DATA frame <length=2829, flags=0x00, stream_id=2>
    [  4.395] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  4.396] recv DATA frame <length=2829, flags=0x00, stream_id=2>
    [  4.602] recv DATA frame <length=5667, flags=0x00, stream_id=6>
    [  4.602] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=6>
              (window_size_increment=33993)
    [  4.602] recv DATA frame <length=2829, flags=0x00, stream_id=2>
    [  4.602] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
              (window_size_increment=33975)
    [  4.808] recv DATA frame <length=4248, flags=0x00, stream_id=6>
    [  4.809] recv DATA frame <length=6379, flags=0x01, stream_id=2>
              ; END_STREAM
    [  5.010] recv DATA frame <length=3536, flags=0x00, stream_id=6>
    [  5.420] recv DATA frame <length=8505, flags=0x00, stream_id=6>
    [  5.420] recv DATA frame <length=5667, flags=0x00, stream_id=6>
    [  5.628] recv DATA frame <length=4248, flags=0x00, stream_id=6>
    [  5.842] recv DATA frame <length=4248, flags=0x00, stream_id=6>
    [  5.842] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  5.842] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
              (window_size_increment=34002)
    [  5.842] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=6>
              (window_size_increment=33281)
    [  6.057] recv DATA frame <length=4248, flags=0x00, stream_id=6>
    [  6.273] recv DATA frame <length=8505, flags=0x00, stream_id=6>
    [  6.490] recv DATA frame <length=9924, flags=0x00, stream_id=6>
    [  6.490] recv DATA frame <length=4248, flags=0x00, stream_id=6>
    [  6.706] recv DATA frame <length=4248, flags=0x00, stream_id=6>
    [  6.706] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
              (window_size_increment=34002)
    [  6.706] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=6>
              (window_size_increment=34002)
    [  6.924] recv DATA frame <length=8505, flags=0x00, stream_id=6>
    [  7.141] recv DATA frame <length=8505, flags=0x00, stream_id=6>
    [  7.361] recv DATA frame <length=8505, flags=0x00, stream_id=6>
    [  7.361] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
              (window_size_increment=34020)
    [  7.574] recv DATA frame <length=9924, flags=0x00, stream_id=6>
    [  7.574] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=6>
              (window_size_increment=34029)
    [  7.787] recv DATA frame <length=9924, flags=0x00, stream_id=6>
    [  7.787] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  7.998] recv DATA frame <length=7086, flags=0x00, stream_id=6>
    [  8.210] recv DATA frame <length=9924, flags=0x00, stream_id=6>
    [  8.210] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
              (window_size_increment=34011)
    [  8.210] send WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=6>
              (window_size_increment=34011)
    [  8.425] recv DATA frame <length=11343, flags=0x00, stream_id=6>
    [  8.426] recv DATA frame <length=2829, flags=0x00, stream_id=6>
    [  8.426] recv DATA frame <length=4053, flags=0x01, stream_id=6>
              ; END_STREAM
    [  8.631] recv DATA frame <length=4443, flags=0x00, stream_id=13>
    [  8.633] recv DATA frame <length=1290, flags=0x01, stream_id=13>
              ; END_STREAM
    [  8.633] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
              (last_stream_id=10, error_code=NO_ERROR(0x00), opaque_data(0)=[])
    

    自然,咱们也得以利用 grep 寻觅出来 server push 的相干 stream:

    nghttp -nv 'https://h2o.examp1e.net' | grep 'PUSH_PROMISE'
    [  1.582] recv PUSH_PROMISE frame <length=59, flags=0x04, stream_id=13>
    [  1.582] recv PUSH_PROMISE frame <length=33, flags=0x04, stream_id=13>
    [  1.582] recv PUSH_PROMISE frame <length=35, flags=0x04, stream_id=13>
    [  1.582] recv PUSH_PROMISE frame <length=24, flags=0x04, stream_id=13>
    [  1.582] recv PUSH_PROMISE frame <length=28, flags=0x04, stream_id=13>
    

    使用 NodeJS 搭建 HTTP/2 服务器

    在大前端的时期背景下,顾客端支出不会点 JavaScript 都快混不下去了,作者目前在作者司前端轮岗了两周,再增加此前也写过 ReactNative,但仍然深感前端变化之快领人惊叹,革命尚未截至,同志仍需努力啊。

    小编们直接上代码:

    var http2 = require('http2');// http2
    var url=require('url'); // https://www.npmjs.com/package/url
    var fs=require('fs'); // https://www.npmjs.com/package/fs
    var mine=require('mine');
    var path=require('path'); // 路径
    
    var server = http2.createServer({
      key: fs.readFileSync('./localhost.key'),
      cert: fs.readFileSync('./localhost.crt')
    }, function(request, response) {
    
        // var pathname = url.parse(request.url).pathname;
        var realPath = './push.json' ;//path.join(pathname,"push.json");    //这里设置自己的文件路径,这是该次response返回的内容;
    
        var pushArray = [];
        var ext = path.extname(realPath);
        ext = ext ? ext.slice(1) : 'unknown';
        var contentType = mine[ext] || "text/plain";
    
        if (fs.existsSync(realPath)) {
    
            console.log('success')
            response.writeHead(200, {
                'Content-Type': contentType
            });
    
            response.write(fs.readFileSync(realPath,'binary'));
    
            // 注意 push 路径必须是绝对路径,这是该次 server push 返回的内容
            var pushItem = response.push('/Users/f.li/Desktop/http2-nodeServer/newpush.json', {
                    response: {
                      'content-type': contentType
                    }    
            });
            pushItem.end(fs.readFileSync('/Users/f.li/Desktop/http2-nodeServer/newpush.json','binary'),()=>{
              console.log('newpush end')
            });
    
            response.end();
    
        } else {
          response.writeHead(404, {
              'Content-Type': 'text/plain'
          });
    
          response.write("This request URL " + realPath + " was not found on this server.");
          response.end();
        }
    
    });
    
    server.listen(3000, function() {
      console.log('listen on 3000');
    });
    

    此处供给小心几点:

    • 创造http2的nodejs服必须得时根据https的,因为前几天主流的浏览器都要支持SSL/TLS的http2,证书和私钥能够自身通过OPENSSL生成。
    • node http2的连锁api和平常的node httpserver一样,可以直接使用。

    利用 nghttp 测验一下大家的代码有未有举行 server push:

    ~ nghttp -nv 'https://localhost:3000/'
    [  0.007] Connected
    The negotiated protocol: h2
    [  0.029] recv SETTINGS frame <length=0, flags=0x00, stream_id=0>
              (niv=0)
    [  0.029] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
              (niv=2)
              [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
              [SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
    [  0.029] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
              ; ACK
              (niv=0)
    [  0.029] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
              (dep_stream_id=0, weight=201, exclusive=0)
    [  0.029] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
              (dep_stream_id=0, weight=101, exclusive=0)
    [  0.029] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
              (dep_stream_id=0, weight=1, exclusive=0)
    [  0.029] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
              (dep_stream_id=7, weight=1, exclusive=0)
    [  0.029] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
              (dep_stream_id=3, weight=1, exclusive=0)
    [  0.029] send HEADERS frame <length=38, flags=0x25, stream_id=13>
              ; END_STREAM | END_HEADERS | PRIORITY
              (padlen=0, dep_stream_id=11, weight=16, exclusive=0)
              ; Open new stream
              :method: GET
              :path: /
              :scheme: https
              :authority: localhost:3000
              accept: */*
              accept-encoding: gzip, deflate
              user-agent: nghttp2/1.21.1
    [  0.043] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
              ; ACK
              (niv=0)
    [  0.049] recv (stream_id=13) :status: 200
    [  0.049] recv (stream_id=13) content-type: text/plain
    [  0.049] recv (stream_id=13) date: Tue, 11 Apr 2017 08:34:46 GMT
    [  0.049] recv HEADERS frame <length=34, flags=0x04, stream_id=13>
              ; END_HEADERS
              (padlen=0)
              ; First response header
    [  0.049] recv DATA frame <length=35, flags=0x00, stream_id=13>
    [  0.049] recv (stream_id=13) :method: GET
    [  0.049] recv (stream_id=13) :scheme: https
    [  0.050] recv (stream_id=13) :authority: localhost:3000
    [  0.050] recv (stream_id=13) :path: /Users/f.li/Desktop/http2-nodeServer/newpush.json
    [  0.050] recv PUSH_PROMISE frame <length=56, flags=0x04, stream_id=13>
              ; END_HEADERS
              (padlen=0, promised_stream_id=2)
    [  0.050] recv DATA frame <length=0, flags=0x01, stream_id=13>
              ; END_STREAM
    [  0.050] recv (stream_id=2) :status: 200
    [  0.050] recv (stream_id=2) date: Tue, 11 Apr 2017 08:34:46 GMT
    [  0.050] recv HEADERS frame <length=2, flags=0x04, stream_id=2>
              ; END_HEADERS
              (padlen=0)
              ; First push response header
    [  0.050] recv DATA frame <length=21, flags=0x00, stream_id=2>
    [  0.050] recv DATA frame <length=0, flags=0x01, stream_id=2>
              ; END_STREAM
    [  0.050] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
              (last_stream_id=2, error_code=NO_ERROR(0x00), opaque_data(0)=[])
    

    看到了 PUSH_PROMISE 的帧,表明进行了 server push。

    一致也能够行使chrome查看 server push,如下图所示:

    美高梅官方网站 7

    chrome 查看 http2 server push

    服务端介绍中央告竣。上面我们来介绍部分 iOS 顾客端对 Server Push 的运用。

    iOS 使用 HTTP/2 Server Push

    Apple 在那地方做的很好,基本完结了顾客端无感调用http/2 server push。不过小编查阅了有一些素材,现在唯有iOS 10 接济 http/2。

    一向上代码吧:

    #import "ViewController.h"
    
    @interface ViewController ()<NSURLSessionDelegate>
    
    @property(nonatomic,strong)NSURLSession *session;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    
    }
    #pragma mark - Touch
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    {
        [self urlSession];
    }
    #pragma mark - 发送请求
    - (void)urlSession
    {
        NSURL *url = [NSURL URLWithString:@"https://localhost:3000"];
    
        //发送HTTPS请求是需要对网络会话设置代理的
        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
        NSURLSessionDataTask *dataTask = [_session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
            // 收到该次请求后,立即请求下次的内容
            [self urlSessionPush];
    
        }];
    
        [dataTask resume];
    }
    
    - (void)urlSessionPush
    {
        NSURL *url = [NSURL URLWithString:@"https://localhost:3000/Users/f.li/Desktop/http2-nodeServer/newpush.json"];
        NSURLSessionDataTask *dataTask = [_session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        }];
        [dataTask resume];
    }
    
    #pragma mark - URLSession Delegate
    - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
    {
        // 这里还要设置下 plist 中设置 ATS
        if (![challenge.protectionSpace.authenticationMethod isEqualToString:@"NSURLAuthenticationMethodServerTrust"])
        {
            return;
        }
        NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
    }
    
    
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics
    {
        NSArray *fetchTypes = @[ @"Unknown", @"Network Load", @"Server Push", @"Local Cache"];
    
        for(NSURLSessionTaskTransactionMetrics *transactionMetrics in [metrics transactionMetrics])
        {
    
            NSLog(@"protocol[%@] reuse[%d] fetch:%@ - %@", [transactionMetrics networkProtocolName], [transactionMetrics isReusedConnection], fetchTypes[[transactionMetrics resourceFetchType]], [[transactionMetrics request] URL]);
    
            if([transactionMetrics resourceFetchType] == NSURLSessionTaskMetricsResourceFetchTypeServerPush)
            {
                NSLog(@"Asset was server pushed");
            }
        }
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    @end
    

    各自看下服务端和客商端的Log:
    客户端:

    Http2ServerPush[2525:274943] protocol[h2] reuse[0] fetch:Network Load - https://localhost:3000/
    Http2ServerPush[2525:274943] {"message":" http2.0 server is ok"}
    Http2ServerPush[2525:274943] protocol[h2] reuse[1] fetch:Server Push - https://localhost:3000/Users/f.li/Desktop/http2-nodeServer/newpush.json
    Http2ServerPush[2525:274943] Asset was server pushed
    Http2ServerPush[2525:274943] {"message":"newPush"}
    

    服务端:

    http2-nodeServer npm start
    
    > http2-nodeServer@1.0.0 start /Users/f.li/Desktop/http2-nodeServer
    > node index.js
    
    listen on 3000
    success
    newpush end
    

    由此看来确实是顾客端发出了四遍呼吁,不过服务端只响应了三回(该次响应+ server push)

    本文相关德姆o

    • Github:lijianfeigeek

    参谋文献

    • HTTP2 Server Push的研究 | AlloyTeam
    • 使用 nghttp2 调试 HTTP/2 流量 | JerryQu 的小站
    • objective c - HTTP/2 Server Push in iOS 10 - Stack Overflow
    • 使用NSURLSession或者AFN发送HTTPS请求 - 简书

    本文由美高梅网投网址发布于Web前端,转载请注明出处:美高梅官方网站原稿出处,李剑飞的博客

    关键词: