【问题标题】:How to completely disable HTTP/1.x support如何完全禁用 HTTP/1.x 支持
【发布时间】:2019-01-02 09:43:47
【问题描述】:

我只想为一个新项目支持 HTTP/2,客户端不是浏览器,所以如果我们根本不支持 HTTP/1.x 也没有问题。

根据我在golang.org/x/net/http2 中看到的内容。我可以使用tls.Listen 并将net.Conn 传递给http2.Server.ServeConn

但是我有点困惑如何在这里使用http2.Transport,谁能给我一个例子?

谢谢

更新:

这是服务器部分,很简单,它是一个回显服务器

package main

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

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

func main() {
    l, err := net.Listen("tcp4", ":1234")
    panicIfNotNil(err)

    s := &http2.Server{}
    sopt := &http2.ServeConnOpts{
        BaseConfig: &http.Server{},
        Handler:    http.HandlerFunc(handler),
    }
    for {
        c, err := l.Accept()
        panicIfNotNil(err)
        go serve(s, sopt, c)
    }
}

func serve(s *http2.Server, sopt *http2.ServeConnOpts, c net.Conn) {
    defer c.Close()
    s.ServeConn(c, sopt)
}

func handler(w http.ResponseWriter, r *http.Request) {
    if r.ProtoMajor != 2 {
        w.WriteHeader(500)
        fmt.Fprintln(w, "Not HTTP/2")
        return
    }
    f, ok := w.(http.Flusher)
    if !ok {
        w.WriteHeader(500)
        fmt.Fprintln(w, "Not Flusher")
        return
    }
    w.Header().Set("Content-Type", "application/octet-stream")
    fmt.Fprintln(w, "Hello World, Echo Server")

    buf := [1024]byte{}
    for {
        n, err := r.Body.Read(buf[:])
        if err == io.EOF {
            break
        }
        panicIfNotNil(err)
        _, err = w.Write(buf[:n])
        f.Flush()
        panicIfNotNil(err)
    }
}

func panicIfNotNil(err error) {
    if err != nil {
        panic(err)
    }
}

curl --http2-prior-knowledge http://127.0.0.1:1234 -d a=b -d c=d -d e=f测试

对于客户端部分,我还在尝试,有什么我会再更新这篇文章的。

更新:

为了简单起见,我这里不使用 TLS

更新:

这是客户端部分

package main

import (
    "crypto/tls"
    "fmt"
    "io"
    "net"
    "net/http"
    "net/url"
    "time"

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

func main() {
    t := &http2.Transport{
        DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
            return net.Dial(network, addr)
        },
        AllowHTTP: true,
    }
    c := &http.Client{
        Transport: t,
    }

    pr, pw := io.Pipe()
    req := &http.Request{
        Method: "POST",
        URL:    mustUrl("http://127.0.0.1:1234/"),
        Body:   pr,
    }
    resp, err := c.Do(req)
    panicIfNotNil(err)
    defer resp.Body.Close()
    if resp.StatusCode != 200 {
        panic(fmt.Errorf("Server return non 200, %d", resp.StatusCode))
    }

    wchan := make(chan struct{})
    go func() {
        buf := [1024]byte{}
        for {
            n, err := resp.Body.Read(buf[:])
            if err == io.EOF {
                break
            }
            panicIfNotNil(err)
            fmt.Printf("GOT DATA %s\n", string(buf[:n]))
        }
        close(wchan)
    }()

    time.Sleep(1 * time.Second)
    pw.Write([]byte("hai AAA"))
    time.Sleep(1 * time.Second)
    pw.Write([]byte("hai BBB"))
    time.Sleep(1 * time.Second)
    pw.Write([]byte("hai CCC"))
    time.Sleep(1 * time.Second)
    pw.Write([]byte("hai CCC"))
    time.Sleep(1 * time.Second)
    pw.Close()

    <-wchan
}

func mustUrl(s string) *url.URL {
    r, err := url.Parse(s)
    panicIfNotNil(err)
    return r
}

func panicIfNotNil(err error) {
    if err != nil {
        panic(err)
    }
}

但不知何故它不起作用 在https://imgur.com/EJV0uGI可以看到网络流量

【问题讨论】:

  • 你能告诉我们你到目前为止尝试/得到了什么吗?
  • @lix 谢谢,我已经更新了问题帖

标签: go http2


【解决方案1】:

在仔细查看 Wireshark 后,我发现了问题,这是因为服务器没有发送任何头帧,因此客户端无法继续处理更多数据。仅仅打印到http.ResponseWriter 并不能确保它被写入网络,而是被缓冲,所以我们需要显式地刷新它。

这解决了问题:

--- main.go 2018-07-25 22:31:44.092823590 +0700
+++ main2.go    2018-07-25 22:32:50.586179879 +0700
@@ -43,6 +43,9 @@
        return
    }
    w.Header().Set("Content-Type", "application/octet-stream")
+   w.WriteHeader(200)
+   f.Flush()
+
    fmt.Fprintln(w, "Hello World, Echo Server")

    buf := [1024]byte{}

【讨论】:

    猜你喜欢
    • 2015-10-07
    • 2017-11-25
    • 2017-11-25
    • 2015-05-15
    • 2023-04-05
    • 1970-01-01
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多