>

今天搞一下http2,复制代码 代码如下

- 编辑:澳门博发娱乐官网 -

今天搞一下http2,复制代码 代码如下

HTTP2 Server Push的研究

2017/01/05 · 基本功工夫 · HTTP/2

原来的书文出处: AlloyTeam   

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

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

一分钟预览 HTTP2 表征和抓包深入分析

2016/09/26 · JavaScript · HTTP/2

原稿出处: 段隆贤   

参谋cnodejs.org下边包车型地铁静态服务器例子,写了下边包车型客车三个nodejs静态服务器例子,里面包蕴cache,压缩,贴代码如下:

1,HTTP2的新特色。

关于HTTP2的新性情,读着能够参照笔者前边的篇章,这里就不在多说了,本篇小说首要讲一下server push那特性子。

HTTP,HTTP2.0,SPDY,HTTPS你应该掌握的有些事

 


继承echo web框架,前些天搞一下http2。

背景

前不久,http互联网需要量日益拉长,以下是httparchive总结,从二〇一三-11-01到贰零壹伍-09-01的伸手数量和传导大小的势头图:

图片 1

 

时下半数以上份客商端&服务端架构的应用程序,都是用http/1.1接连的,当代浏览器与单个域最利兹接数,都在4-6个左右,由上海体育场面Total Requests数据,如若不用CDN分流,平均有十八个左右的串行须求。
HTTP2 是一九九九年发布http1.1后的三回首要的改革,在情商层面改良了上述难点,降低能源占用,来,直接感受一下差距:

HTTP/2 is the future of the Web, and it is here!
那是 Akamai 公司创设的三个法定的演示,用以评释 HTTP/2 相比较于事先的 HTTP/1.1 在质量上的特大进步。 同期呼吁 379 张图片,从Load time 的自己检查自纠能够见见 HTTP/2 在进程上的优势。

图片 2

 

本文全体源码和抓包文件在github

复制代码 代码如下:

2,Server Push是什么。

简言之来讲就是当客户的浏览器和服务器在创设链接后,服务器主动将一部分财富推送给浏览器并缓存起来,那样当浏览器接下去央浼这个财富时就直接从缓存中读取,不会在从服务器上拉了,提高了速率。举一个例证正是:

譬喻三个页面有3个财富文件index.html,index.css,index.js,当浏览器央浼index.html的时候,服务器不止重临index.html的剧情,同一时间将index.css和index.js的源委push给浏览器,当浏览器下一次伏乞那2多少个文件时就可以平昔从缓存中读取了。

图片 3

HTTP2

What is HTTP/2?
HTTP/2 is a replacement for how HTTP is expressed “on the wire.” It is not a ground-up rewrite of the protocol; HTTP methods, status codes and semantics are the same, and it should be possible to use the same APIs as HTTP/1.x (possibly with some small additions) to represent the protocol.

The focus of the protocol is on performance; specifically, end-user perceived latency, network and server resource usage. One major goal is to allow the use of a single connection from browsers to a Web site.

新的二进制格式(Binary Format)
HTTP1.x的分析是依照文本。基于文本合同的格式分析存在后天破绽,文本的表现情势有各类性,要做到健壮性思虑的场景必然比非常多,二进制则差异,只认0和1的结合。基于这种思量HTTP2.0的磋商解析决定利用二进制格式,完毕方便且健壮。

多路复用(MultiPlexing)
即延续分享,即每一个request都以是作为连接分享机制的。三个request对应一个id,那样一个老是上能够有四个request,每一个连接的request能够随意的混杂在联合具名,接收方可以根据request的 id将request再归属到个别差异的服务端诉求里面。多路复用原理图:

header压缩
HTTP2.0利用encoder来减弱要求传输的header大小,通讯双方各自cache一份header 田野先生s表,既制止了双重header的传导,又减小了亟待传输的大大小小。

服务端推送(server push)
同SPDY一样,HTTP2.0也具有server push功能。

HTTP/2 源自 SPDY/2

SPDY 类别左券由谷歌(Google)开销,于 二〇一〇 年公开。它的安排性目的是下落 贰分之一的页面加载时间。当下广大资深的互连网厂商都在和谐的网址或 应用软件 中选拔了 SPDY 种类合同(当前流行版本是 SPDY/3.1),因为它对品质的进级是一览无余的。主流的浏览器(Google、火狐、Opera)也都早就经支撑 SPDY,它已经化为了工业规范,HTTP Working-Group 最终决定以 SPDY/2 为根基,开辟 HTTP/2。HTTP/2标准于二零一五年三月以MuranoFC 7540正规发布。

而是,HTTP/2 跟 SPDY 仍有例外的地方,重如若以下两点:

HTTP/2 辅助明文 HTTP 传输,而 SPDY 强制行使 HTTPS
HTTP/2 新闻头的压缩算法采纳 HPACK ,而非 SPDY 选拔的 DEFLATE(感激网民 逸风之狐指正)

共谋文书档案请见:rfc7540:HTTP2

/**
 * 静态文件服务器测验例子
 * User: xuwm
 * Date: 13-5-17
 * Time: 上午8:38
 * To change this template use File | Settings | File Templates.
 */
var port=3333;
var http = require("http");
var url = require("url");
var fs = require("fs");
var path = require("path");
var mime = require("./mime").types;
var config = require("./config");
var zlib = require("zlib");
//创建http服务端
var server=http.createServer(function(request,response){
    var obj= url.parse(request.url);
    response.setHeader("Server","Node/V8");
    console.log(obj);
    var pathname=obj.pathname;
    if(pathname.slice(-1)==="/"){
        pathname=pathname+config.Welcome.file;   //暗中同意取当前暗许下的index.html
    }
    var realPath = path.join("assets", path.normalize(pathname.replace(/../g, "")));
    console.log(realPath) ;
    var pathHandle=function(realPath){
    //用fs.stat方法获得文件
        fs.stat(realPath,function(err,stats){
            if(err){
                response.writeHead(404,"not found",{'Content-Type':'text/plain'});
                response.write("the request "+realPath+" is not found");
                response.end();
            }else{
                if(stats.isDirectory()){
                }else{
                    var ext = path.extname(realPath);
                    ext = ext ? ext.slice(1) : 'unknown';
                    var contentType = mime[ext] || "text/plain";
                    response.setHeader("Content-Type", contentType);

3,Server Push原理是什么。

要想明白server push原理,首先要驾驭一些概念。大家精晓HTTP2传输的格式并不像HTTP1使用文本来传输,而是启用了二进制帧(Frames)格式来传输,和server push相关的帧重要分为那二种等级次序:

  1. HEADEENVISIONS 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经常的出殡和埋葬HEADELANDS 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的能源后会缓存起来当呼吁那一个财富时会从间接从从缓存中读取。

下图表示了全数流程:

图片 4

HTTP/2

变迁证书

go run C:gosrccryptotlsgenerate_cert.go --host localhost
2017/11/22 10:06:58 written cert.pem
2017/11/22 10 :06:58 written key.pem

HTTP2个性大概浏览

                    var lastModified = stats.mtime.toUTCString();
                    var ifModifiedSince = "If-Modified-Since".toLowerCase();
                    response.setHeader("Last-Modified", lastModified);

4,Server Push怎么用。

既然server push这么奇妙,那么大家怎么着使用啊?怎么设置服务器push哪些文件呢?

先是并非兼具的服务器都帮助server push,nginx最近还不帮忙那些特点,能够在nginx的官方博客上收获验证,然则Apache和nodejs都早已支撑了server push那三个特征,必要证美素佳儿(Friso)些的是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,同一时候也得以说明多路复用的特征。

图片 5

那边要求留神几点:

  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到大家的浏览器,我们得以在浏览器中查看:

图片 6

能够见到,运维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多少个文件时就能够直接从缓存中读取了。

如下图所示:

图片 7

Apple-http2ServerPush

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

1. 二进制左券

HTTP/2 选取二进制格式传输数据,而非 HTTP/1.x 的文本格式

图片 8

 

由上海教室能够见见HTTP2在原先的应用层和HTTP层增加了一层二进制传输。

二进制合同的三个功利是,能够定义额外的帧。

HTTP/2 定义了近十种帧(详细情况可剖判抓包文件),为今后的高档应用打好了基础。如若运用文本达成这种效应,分析数据将会变得不行麻烦,二进制解析则有利得多。
RFC7540:Frame Definitions

图片 9

磋商业中学定义的帧

                    if (ext.match(config.Expires.fileMatch)) {
                        var expires = new Date();
                        expires.setTime(expires.getTime() + config.Expires.maxAge * 1000);
                        response.setHeader("Expires", expires.toUTCString());
                        response.setHeader("Cache-Control", "max-age=" + config.Expires.maxAge);
                    }

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

图片 10

HTTP/2 Server Push 原理是何等

要想了然server push原理,首先要明了一些定义。大家知晓HTTP/2传输的格式并不像HTTP1使用文本来传输,而是启用了二进制帧(Frames)格式来传输,和server push相关的帧重要分为这几体系型:

  1. HEADE奥迪Q3S 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/第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符合规律的发送HEADEQX56S frame和DATA frames将index.html的内容再次回到给client。
  5. client接收到PUSH_PROMISE frame得知stream 2和stream 3来接收推送能源。
  6. server获得index.css和index.js便会发送HEADECR-VS frame和DATA frames将能源发送给client。
  7. client获得push的财富后会缓存起来当呼吁这么些能源时会从第一手从从缓存中读取。

golang.org/x/net/http2

文书档案地址:

获取:
get golang.org/x/net/http2

代码main.go:

package main

import (
    "fmt"
    "html"
    "log"
    "net/http"

    "golang.org/x/net/http2"
)

func main() {
    var srv http.Server
    http2.VerboseLogs = true
    srv.Addr = ":8080"
    // This enables http2 support
    http2.ConfigureServer(&srv, nil)

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hi tester %qn", html.EscapeString(r.URL.Path))
        ShowRequestInfoHandler(w, r)
    })
    // Listen as https ssl server
    // NOTE: WITHOUT SSL IT WONT WORK!!
    log.Fatal(srv.ListenAndServeTLS("cert.pem", "key.pem"))
}
func ShowRequestInfoHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/plain")
    fmt.Fprintf(w, "Method: %sn", r.Method)
    fmt.Fprintf(w, "Protocol: %sn", r.Proto)
    fmt.Fprintf(w, "Host: %sn", r.Host)
    fmt.Fprintf(w, "RemoteAddr: %sn", r.RemoteAddr)
    fmt.Fprintf(w, "RequestURI: %qn", r.RequestURI)
    fmt.Fprintf(w, "URL: %#vn", r.URL)
    fmt.Fprintf(w, "Body.ContentLength: %d (-1 means unknown)n", r.ContentLength)
    fmt.Fprintf(w, "Close: %v (relevant for HTTP/1 only)n", r.Close)
    fmt.Fprintf(w, "TLS: %#vn", r.TLS)
    fmt.Fprintf(w, "nHeaders:n")
    r.Header.Write(w)
}

浏览器输入:

结果:

Hi tester "/"
Method: GET
Protocol: HTTP/2.0
Host: localhost:8080
RemoteAddr: [::1]:2750
RequestURI: "/"
URL: &url.URL{Scheme:"", Opaque:"", User:(*url.Userinfo)(nil), Host:"", Path:"/", RawPath:"", ForceQuery:false, RawQuery:"", Fragment:""}
Body.ContentLength: 0 (-1 means unknown)
Close: false (relevant for HTTP/1 only)
TLS: &tls.ConnectionState{Version:0x303, HandshakeComplete:true, DidResume:false, CipherSuite:0xc02f, NegotiatedProtocol:"h2", NegotiatedProtocolIsMutual:true, ServerName:"localhost", PeerCertificates:[]*x509.Certificate(nil), VerifiedChains:[][]*x509.Certificate(nil), SignedCertificateTimestamps:[][]uint8(nil), OCSPResponse:[]uint8(nil), TLSUnique:[]uint8{0xa6, 0x3c, 0xfe, 0x93, 0x3c, 0x15, 0x4f, 0x74, 0xfc, 0x97, 0xca, 0x73}}

Headers:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Alexatoolbar-Alx_ns_ph: AlexaToolbar/alx-4.0
Cookie: _ga=GA1.1.981224509.1509938615
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36

2. 多路复用

HTTP/2 复用TCP连接,在三个总是里,客户端和浏览器都得以同期发送三个哀告或应对,何况不要遵照顺序依次对应,那样就防止了”队头堵塞”(见TCP/IP详解卷一)。
各种 Frame Header 都有三个 Stream ID 就是被用于落到实处该特性。每一次须求/响应使用差别的 Stream ID。就好像同一个 TCP 链接上的数额包通过 IP: PORT 来区分出多少包去往哪个地方一样。

图片 11

rfc7540: HTTP2 Multiplexing中对Multiplexing的说明

Streams and Multiplexing A "stream" is an independent, bidirectional sequence of frames exchanged between the client and server within an HTTP/2 connection. Streams have several important characteristics: o A single HTTP/2 connection can contain multiple concurrently open streams, with either endpoint interleaving frames from multiple streams. o Streams can be established and used unilaterally or shared by either the client or server. o Streams can be closed by either endpoint. o The order in which frames are sent on a stream is significant. Recipients process frames in the order they are received. In particular, the order of HEADERS and DATA frames is semantically significant. o Streams are identified by an integer. Stream identifiers are assigned to streams by the endpoint initiating the stream.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Streams and Multiplexing
 
   A "stream" is an independent, bidirectional sequence of frames
   exchanged between the client and server within an HTTP/2 connection.
   Streams have several important characteristics:
 
   o  A single HTTP/2 connection can contain multiple concurrently open
      streams, with either endpoint interleaving frames from multiple
      streams.
 
   o  Streams can be established and used unilaterally or shared by
      either the client or server.
 
   o  Streams can be closed by either endpoint.
 
   o  The order in which frames are sent on a stream is significant.
      Recipients process frames in the order they are received.  In
      particular, the order of HEADERS and DATA frames is semantically
      significant.
 
   o  Streams are identified by an integer.  Stream identifiers are
      assigned to streams by the endpoint initiating the stream.

                    if (request.headers[ifModifiedSince] && lastModified == request.headers[ifModifiedSince]) {
                        console.log("从浏览器cache里取")
                        response.writeHead(304, "Not Modified");
                        response.end();
                    } else {
                        var raw = fs.createReadStream(realPath);
                        var acceptEncoding = request.headers['accept-encoding'] || "";
                        var matched = ext.match(config.Compress.match);

Server Push 怎么用

Server Push

Server Push是什么

简单易行来说正是当客商的浏览器和服务器在创设链接后,服务器主动将一些财富推送给浏览器并缓存起来,那样当浏览器接下去央浼那么些财富时就直接从缓存中读取,不会在从服务器上拉了,提高了速率。举一个例证就是:
假若三个页面有3个财富文件index.html,index.css,index.js,当浏览器须要index.html的时候,服务器不独有重临index.html的剧情,同期将index.css和index.js的剧情push给浏览器,当浏览器下一次呼吁那2多个文件时就足以一向从缓存中读取了。

Server Push原理是何许

要想驾驭server push原理,首先要明了一些定义。大家领会HTTP2传输的格式并不像HTTP1使用文本来传输,而是启用了二进制帧(Frames)格式来传输,和server push相关的帧首要分为那二种档案的次序:

HEADE酷威S frame(必要重回头帧):这种帧主要辅导的http央求头音信,和HTTP1的header类似。

DATA frames(数据帧) :这种帧寄放真正的数码content,用来传输。
PUSH_PROMISE frame(推送帧):这种帧是由server端发送给client的帧,用来代表server push的帧,这种帧是促成server push的要害帧类型。

RST_STREAM(撤销推送帧):这种帧表示诉求关闭帧,轻易讲便是当client不想接受某个能源照旧收受timeout时会向发送方发送此帧,和PUSH_PROMISE frame一齐行使时表示拒绝可能关闭server push。

叩问了相关的帧类型,上面正是现实server push的兑现进度了:
由多路复用大家能够领略HTTP第22中学对此同二个域名的乞求会接纳一条tcp链接而用差异的stream ID来区分各自的伸手。
当client使用stream 1诉求index.html时,server平常管理index.html的呼吁,并得以得知index.html页面还将要会呈请index.css和index.js。
server使用stream 1发送PUSH_PROMISE frame给client告诉client小编这边可以运用stream 2来推送index.js和stream 3来推送index.css能源。
server使用stream 1平常的发送HEADE逍客S frame和DATA frames将index.html的内容再次来到给client。
client接收到PUSH_PROMISE frame得知stream 2和stream 3来接收推送能源。
server获得index.css和index.js便会发送HEADE逍客S frame和DATA frames将能源发送给client。
client得到push的财富后会缓存起来当呼吁这些财富时会从第一手从从缓存中读取。

3. 数据流

数据流发送到八分之四的时候,客户端和服务器都能够发送时域信号(如虎 CTR 3ST_STREAM帧),撤销那么些数据流。1.1版撤废数据流的无与伦比格局,正是关门TCP连接。那正是说,HTTP/2 能够撤消某三遍呼吁,同期确认保障TCP连接还展开着,能够被其余诉求使用。

                        if (matched && acceptEncoding.match(/bgzipb/)) {
                            response.writeHead(200, "Ok", {'Content-Encoding': 'gzip'});
                            raw.pipe(zlib.createGzip()).pipe(response);
                        } else if (matched && acceptEncoding.match(/bdeflateb/)) {
                            response.writeHead(200, "Ok", {'Content-Encoding': 'deflate'});
                            raw.pipe(zlib.createDeflate()).pipe(response);
                        } else {
                            response.writeHead(200, "Ok");
                            raw.pipe(response);
                        }
                    }
                }
            }
        });

使用 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 品质测量检验工具;

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

4. 头音讯压缩:

HTTP/2 对新闻头选拔 HPACK 实行削减传输,能够节约信息头占用的网络的流量。而 HTTP/1.x 每便央求,都会带走大批量冗余头音讯,浪费了数不清带宽财富。
HTTP2对http头建立索引表,一样的头只发送hash table 的index, 同一时间还用了霍夫曼编码和理念的gzip压缩。

    }
    pathHandle(realPath);
});
server.listen(port);
console.log("http server run in port:"+port);

本文由胜博发-前端发布,转载请注明来源:今天搞一下http2,复制代码 代码如下