如何让我的用 Golang 编写的 Web 服务器支持 HTTP/2 服务器推送?

Posted

技术标签:

【中文标题】如何让我的用 Golang 编写的 Web 服务器支持 HTTP/2 服务器推送?【英文标题】:How to Make My Web Server written in Golang to support HTTP/2 Server Push? 【发布时间】:2017-05-20 07:28:35 【问题描述】:

我的 Web 服务器是用 Golang 编码的,并且支持 HTTPS。我希望利用 Web 服务器中的 HTTP/2 服务器推送功能。以下链接解释了如何将 HTTP 服务器转换为支持 HTTP/2:- https://www.ianlewis.org/en/http2-and-go 但是,目前尚不清楚如何在 Golang 中实现服务器推送通知。 - 我应该如何添加服务器推送功能? - 我如何控制或管理要推送的文档和文件?

【问题讨论】:

信息不多,但关于主题:***.com/questions/37872924/… 请注意,“推送通知”与“服务器推送”不同。顺便说一句,我在 Google AppEngine 中运行 Go 的经验是,我需要设置如下的 http 标头来指示要推送的文件:link:/bg.jpg>;相对=预载; as=图像,;相对=预载; as=脚本 rakyll.org/http2push 【参考方案1】:

Go 1.7 及更早版本不支持标准库中的 HTTP/2 服务器推送。即将发布的 1.8 版本中将添加对服务器推送的支持(请参阅release notes,预计发布时间为 2 月)。

在 Go 1.8 中,您可以使用新的 http.Pusher 接口,该接口由 net/http 的默认 ResponseWriter 实现。如果服务器推送不支持 (HTTP/1) 或不允许(客户端已禁用服务器推送),Pushers Push 方法返回 ErrNotSupported。

例子:

package main                                                                              

import (
    "io"
    "log"
    "net/http"
)

func main() 
    http.HandleFunc("/pushed", func(w http.ResponseWriter, r *http.Request) 
        io.WriteString(w, "hello server push")
    )

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) 
        if pusher, ok := w.(http.Pusher); ok 
            if err := pusher.Push("/pushed", nil); err != nil 
                log.Println("push failed")
            
        

        io.WriteString(w, "hello world")
    )

    http.ListenAndServeTLS(":443", "server.crt", "server.key", nil)

如果你想在 Go 1.7 或更早版本中使用服务器推送,可以使用 golang.org/x/net/http2 并直接写入帧。

【讨论】:

Go 1.8 也将于 2 月发布。【参考方案2】:

正如其他答案中提到的,您可以使用 Go 1.8 功能(将作者转换为 http.Pusher,然后使用 Push 方法)。

附带一个警告:您必须直接从您的服务器提供 HTTP2 流量。

如果您使用 nginx 之类的代理,这可能不起作用。如果您想考虑这种情况,您可以使用Link 标头来通告要推送的 URL。

// In the case of HTTP1.1 we make use of the `Link` header
// to indicate that the client (in our case, NGINX) should
// retrieve a certain URL.
//
// See more at https://www.w3.org/TR/preload/#server-push-http-2.
func handleIndex(w http.ResponseWriter, r *http.Request) 
  var err error

  if *http2 
    pusher, ok := w.(http.Pusher)
    if ok 
      must(pusher.Push("/image.svg", nil))
    
   else 
    // This ends up taking the effect of a server push
    // when interacting directly with NGINX.
    w.Header().Add("Link", 
      "</image.svg>; rel=preload; as=image")
  

  w.Header().Add("Content-Type", "text/html")
  _, err = w.Write(assets.Index)
  must(err)

ps.:如果您有兴趣,我在这里https://ops.tips/blog/nginx-http2-server-push/ 写了更多关于此的内容。

【讨论】:

以上是关于如何让我的用 Golang 编写的 Web 服务器支持 HTTP/2 服务器推送?的主要内容,如果未能解决你的问题,请参考以下文章

如何让我的消费者使用 Azure sdk for Golang v0.3.1 监听 Azure 服务总线上的消息?

带你用 Go 搭建一个最简单的 Web 服务了解 Golang 运行 web 的原理

如何让我的 Discord Bot 用 Ja​​vascript 编写以更快地发送消息?

如何让我的简单 Java Web 服务正常工作?

Golang Web入门:自顶向下理解Http服务器

Golang Web入门:自顶向下理解Http服务器