原文出处,李剑飞的博客

时间:2019-11-01 22:00来源:美高梅游戏网站
5,Server Push相关问题。 我们知道现在我们web的资源一般都是放在CDN上的,那么CDN的优势和serverpush的优势有何区别呢,到底是哪个比较快呢?这个问题笔者也一直在研究,本文的相关d

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 收藏 评论

图片 1

使用 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 性能测试工具;

生命不止,继续 go go go !!!

HTTP2 Server Push的研究

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

原文出处: AlloyTeam   

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的资源后会缓存起来当请求这个资源时会从直接从从缓存中读取。

继续echo web框架,今天搞一下http2。

2,Server Push是什么。

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

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

HTTP/2 Server Push 是什么

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

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

如下图所示:

图片 2

Apple-http2ServerPush

Golang1.8中的Server Push

代码main.go:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

var image []byte

// preparing image
func init() {
    var err error
    image, err = ioutil.ReadFile("./image.png")
    if err != nil {
        panic(err)
    }
}

// Send HTML and push image
func handlerHtml(w http.ResponseWriter, r *http.Request) {
    pusher, ok := w.(http.Pusher)
    if ok {
        fmt.Println("Push /image")
        pusher.Push("/image", nil)
    }
    w.Header().Add("Content-Type", "text/html")
    fmt.Fprintf(w, `<html><body><img src="/image"></body></html>`)
}

// Send image as usual HTTP request
func handlerImage(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "image/png")
    w.Write(image)
}
func main() {
    http.HandleFunc("/", handlerHtml)
    http.HandleFunc("/image", handlerImage)
    fmt.Println("start http listening :18443")
    err := http.ListenAndServeTLS(":18443", "server.crt", "server.key", nil)
    fmt.Println(err)
}

浏览器输入:

可以使用插件HTTP/2 and SPDY indicator
chrome://net-internals/#http2

1,HTTP2的新特性。

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

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

 

本文相关Demo

  • Github:lijianfeigeek

echo中的HTTP/2

代码main.go:

package main

import (
    "fmt"
    "net/http"

    "github.com/labstack/echo"
)

func main() {
    e := echo.New()
    e.GET("/request", func(c echo.Context) error {
        req := c.Request()
        format := `
            <code>
                Protocol: %s<br>
                Host: %s<br>
                Remote Address: %s<br>
                Method: %s<br>
                Path: %s<br>
            </code>
        `
        return c.HTML(http.StatusOK, fmt.Sprintf(format, req.Proto, req.Host, req.RemoteAddr, req.Method, req.URL.Path))
    })
    e.Logger.Fatal(e.StartTLS(":1323", "cert.pem", "key.pem"))
}

浏览器输入:

结果:

Protocol: HTTP/2.0
Host: localhost:1323
Remote Address: [::1]:1905
Method: GET
Path: /request

如果出现错误:
http: TLS handshake error from [::1]:1735: tls: first record does not look like a TLS handshake.

请检查是否输入的是https

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 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有兴趣的可以尝试一下。

nghttp

nghttp 做为一个功能完整的 HTTP/2 客户端,非常适合用来查看和调试 HTTP/2 流量。它支持的参数很多,通过官方文档或者 nghttp -h 都能查看。最常用几个参数如下:

  • -v, --verbose,输出完整的 debug 信息;
  • -n, --null-out,丢弃下载的数据;
  • -a, --get-assets,下载 html 中的 css、js、image 等外链资源;
  • -H, --header = < HEADER >,添加请求头部字段,如 -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>

echo框架中的Server Push

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>HTTP/2 Server Push</title>
  <link rel="stylesheet" href="/app.css">
  <script src="/app.js"></script>
</head>
<body>
  <img class="echo" src="/echo.png">
  <h2>The following static files are served via HTTP/2 server push</h2>
  <ul>
    <li><code>/app.css</code></li>
    <li><code>/app.js</code></li>
    <li><code>/echo.png</code></li>
  </ul>
</body>
</html>

main.go

package main

import (
    "net/http"

    "github.com/labstack/echo"
)

func main() {
    e := echo.New()
    e.Static("/", "static")
    e.GET("/", func(c echo.Context) (err error) {
        pusher, ok := c.Response().Writer.(http.Pusher)
        if ok {
            if err = pusher.Push("/app.css", nil); err != nil {
                return
            }
            if err = pusher.Push("/app.js", nil); err != nil {
                return
            }
            if err = pusher.Push("/echo.png", nil); err != nil {
                return
            }
        }
        return c.File("index.html")
    })
    e.Logger.Fatal(e.StartTLS(":1323", "cert.pem", "key.pem"))
}

浏览器输入:

参考:

图片 5

编辑:美高梅游戏网站 本文来源:原文出处,李剑飞的博客

关键词:

  • 上一篇:没有了
  • 下一篇:没有了