乐趣区

关于golang:HTTP2服务器推送的第一次尝试

来自公众号:新世界杂货铺

在 HTTP1.x 中,拜访一个页面,浏览器首先获取 HTML 资源,而后在解析页面时增量地获取其余资源,服务器必须期待浏览器发出请求后才下发页面内资源。而服务器实际上是晓得页面内资源有哪些的,如果服务器可能在浏览器显式申请资源之前就将资源推送到浏览器,页面加载速度将会大大提醒,这也是本篇的宗旨。

本篇次要分为两个局部,第一局部是用 go 实现的服务器推送例子,第二局部是自签名证书。为什么会有自签名证书,这里笔者先卖个关子,持续浏览后文将会守得云开见月明。

服务器推送例子

目前仅有 HTTP2 反对服务器推送,HTTP1.x 不反对服务器推送,那咱们在代码中应该如何判断以后服务器是否反对推送?

在 Go 中,咱们通过判断 http.ResponseWriter 是否实现了 http.Pusher 接口就能够晓得以后服务器是否反对推送。

上面为笔者写下的第一个服务器推送例子:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {http.NotFound(w, r)
        return
    }
    pusher, ok := w.(http.Pusher)
    if ok {
        // 被动推送服务资源
        if err := pusher.Push("/static/app.js", nil); err != nil {log.Printf("Failed to push: %v", err)
        }
        if err := pusher.Push("/static/style.css", nil); err != nil {log.Printf("Failed to push: %v", err)
        }
    }
    // 下发浏览器首屏资源
    fmt.Fprintf(w, `<html>
    <head>
        <title> 新世界杂货铺 </title>
        <link rel="stylesheet" href="/static/style.css"">
    </head>
    <body>
        <div>Hello 新世界杂货铺 </div>
        <div id="content"></div>
        <script src="/static/app.js"></script>
    </body>
    </html>`)
})
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
http.ListenAndServe(":8080", nil)

上述代码中 app.js 内容如下:

document.getElementById("content").innerHTML = '"新世界杂货铺" from js'

运行上述代码后,在浏览器中拜访 http://localhost:8080/ 失去如下后果:

咱们看上图中标红局部发现 js 资源和款式资源并不是服务器推送下发的,而且应用的是HTTP1.1,联合笔者后面的文章晓得 Go 是反对 HTTP2 的且 HTTP2 须要应用 SSL/TLS 即 HTTPS。因而,笔者批改监听代码如下:

http.ListenAndServeTLS(":8080", "ca.crt", "ca.key", nil)

再次运行上述代码,并在浏览器中拜访 https://localhost:8080/ 失去如下后果:

咱们看图中红色局部知本次申请应用了 HTTP2 协定,并且动态资源由服务器推送。

上述代码中 ca.crtca.key别离为自签名证书以及私钥,该证书及私钥已上传至笔者的 github,github 链接见文末。

生成自签名证书

注:笔者生成证书环境为 macOS

笔者生成自签名证书时,先祭出搜寻大法,而后应用网上的命令生成证书,最初证书是生成了,然而运行上述例子后在浏览器中的拜访后果却不尽人意。

首先执行下述命令生成证书:

// 生成私钥
openssl genrsa -out old.key 2048
// 生成证书签名申请,此时须要填写一些证书信息
openssl req -new -key old.key -out old.csr
// 签发证书
openssl x509 -req -days 365 -in old.csr -signkey old.key -out old.crt

批改例子中的证书和私钥为 old.crtold.key,最初在 Chrome 浏览器中拜访后果如下:

上述页面给了不平安提醒却无奈持续不平安拜访(Safari 浏览器能够进行不平安地拜访),作为一个轻微强迫症患者,笔者的心田有一丝丝好受。

于是笔者翻了 openssl 官网,最初对生成自签名证书的命令做了改良。

首先在执行命令的目录创立一个ca.cnf(能够随便命名),并在该文件中写入如下内容:

# 更多 x509v3_config 见 https://www.openssl.org/docs/man1.1.1/man5/x509v3_config.html
[ca_conf]
extendedKeyUsage = serverAuth # 可能持续进行不平安地拜访的要害
basicConstraints = CA:FALSE

改良后的签名命令如下:

// 生成私钥
openssl genrsa -out ca.key 2048
// 生成证书签名申请,此时须要填写一些证书信息
openssl req -new -key ca.key -out ca.csr
// 签发证书
openssl x509 -req -sha256 -extfile ca.cnf -extensions ca_conf -days 365 -in ca.csr -signkey ca.key -out ca.crt

此证书即为后面例子所应用的证书,并且第一次在浏览器中拜访会有如下提醒:

点击图中红框局部即可失常拜访页面。

什么时候应用推送

实现下面的例子之后,笔者特意去察看了百度、淘宝和谷歌的首页发现大家均已开始应用 HTTP2,然而如同还没有公司应用服务器推送。

因而笔者上面的总结全凭集体教训猜想:

  1. 服务器推送不要滥用,仅推送影响该页面展现的要害资源,毕竟前端的懒加载曾经非常成熟。
  2. 浏览器可能对资源进行缓存,对于曾经缓存了的资源持续推送没有意义,所以这种场景下要防止二次推送。

最初,衷心希望本文可能对各位读者有肯定的帮忙。

参考

https://blog.golang.org/h2push

https://blog.csdn.net/qq_4187…

注:

  1. 写本文时,笔者所用 go 版本为: go1.15.2
  2. 文章中所用残缺例子:https://github.com/Isites/go-…
退出移动版