通过HTTP2运输获得意外的EOF

发布于 2025-01-30 12:38:37 字数 885 浏览 1 评论 0 原文

在GO中尝试HTTP2软件包,在创建HTTP2连接时,我会遇到意外的EOF错误。无法找出确切的问题。

    tcpConn, err := net.Dial("tcp", "clients1.google.com:443")
    if err != nil {
        panic(err)
    }
    defer tcpConn.Close()

    t := http2.Transport{}
    http2ClientConn, err := t.NewClientConn(tcpConn)
    if err != nil {
        panic(err)
    }

    req, err := http.NewRequest("GET", "https://clients1.google.com/generate_204", nil)
    if err != nil {
        panic(err)
    }

    resp, err := http2ClientConn.RoundTrip(req)
    if err != nil {
        panic(err) // getting unexpected EOF
    }

    defer resp.Body.Close()
    fmt.Println(resp.StatusCode)

输出

panic: unexpected EOF

goroutine 1 [running]:
main.main()
        /Users/rishabharya/Desktop/Projects/src/github.com/rishabh-arya95/raw_http/main.go:31 +0x217
exit status 2

Was trying out the http2 package in go, and while creating an HTTP2 connection I am getting an unexpected EOF error. Not able to figure out the exact issue.

    tcpConn, err := net.Dial("tcp", "clients1.google.com:443")
    if err != nil {
        panic(err)
    }
    defer tcpConn.Close()

    t := http2.Transport{}
    http2ClientConn, err := t.NewClientConn(tcpConn)
    if err != nil {
        panic(err)
    }

    req, err := http.NewRequest("GET", "https://clients1.google.com/generate_204", nil)
    if err != nil {
        panic(err)
    }

    resp, err := http2ClientConn.RoundTrip(req)
    if err != nil {
        panic(err) // getting unexpected EOF
    }

    defer resp.Body.Close()
    fmt.Println(resp.StatusCode)

Output

panic: unexpected EOF

goroutine 1 [running]:
main.main()
        /Users/rishabharya/Desktop/Projects/src/github.com/rishabh-arya95/raw_http/main.go:31 +0x217
exit status 2

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

抚笙 2025-02-06 12:38:37

您应该使用 tls 应用程序层协议协议协议(alpn)。

会发生什么?

  1. 客户端建立与服务器的网络连接。
  2. 客户端 sends 使用 https://datatracker.ietf.org/doc/html/rfc7540“ rel =“ nofollow noreferrer”> http/2协议
  3. 服务器接收数据并期望它成为 tls ://datatracker.ietf.org/doc/html/rfc84446#section-4“ rel =“ nofollow noreferrer”>握手协议。
  4. 服务器必须关闭连接,因为数据不满足 tls 协议。
  5. An io.errunennefectedeof 由于在读取响应之前已关闭连接,因此返回了错误。

客户需要更改的

客户建立了与 standard htttps 端口(端口号为 443 ),但使用 net.dial()函数。 https 协议使用 通过Internet保护HTTP连接。因此,客户必须使用 tls.dial()函数来建立连接:

tcpConn, err := tls.Dial("tcp", "clients1.google.com:443", new(tls.Config))

但是,客户端不能使用空的 tls配置。在这种特殊情况下,服务器支持这两个协议: http/1.1 =“ https://datatracker.ietf.org/doc/html/rfc2818” rel =“ nofollow noreferrer”> http/2 。默认情况下,服务器使用HTTP/1.1协议。请求使用http/2协议有两种方法:

第二种方法不合适。第一个原因是 http2 软件包不打算为此。第二个原因是服务器忽略了给定请求的HTTP升级机制。

为了使用第一个方法,我们需要添加“ H2” “ a> to受支持的应用级协议列表(所有已注册的标识符可以在

conf := & tls.Config {
    NextProtos: []string{"h2"},
}

tcpConn, err := tls.Dial("tcp", "clients1.google.com:443", conf)

工作代码

package main

import (
    "crypto/tls"
    "fmt"
    "net/http"

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

func main() {
    conf := & tls.Config {
        NextProtos: []string{"h2"},
    }
    tcpConn, err := tls.Dial("tcp", "clients1.google.com:443", conf)
    if err != nil {
        panic(err)
    }
    defer tcpConn.Close()

    t := http2.Transport{}
    http2ClientConn, err := t.NewClientConn(tcpConn)
    if err != nil {
        panic(err)
    }

    req, err := http.NewRequest("GET", "https://clients1.google.com/generate_204", nil)
    if err != nil {
        panic(err)
    }

    resp, err := http2ClientConn.RoundTrip(req)
    if err != nil {
        panic(err)
    }

    defer resp.Body.Close()
    fmt.Println(resp.StatusCode)

}

和略修改版本


curl 是一个方便的检查工具。

进行http/2请求:

 $ curl -i --http2 https://clients1.google.com/generate_204
-| HTTP/2 204

禁用应用程序层协议协议(ALPN):

 $ curl -i --http2 --no-alpn https://clients1.google.com/generate_204
-| HTTP/1.1 204 No Content

在没有应用程序层协议协议(ALPN)的情况下发送HTTP/2请求:

 $ curl -i --http2-prior-knowledge --no-alpn https://clients1.google.com/generate_204
-| curl: (52) Empty reply from server

错误 52 :服务器没有回复任何内容,在这里被认为是错误。

参数 描述
- i 在输出中包括HTTP响应标头。
- v 在操作过程中使卷曲冗长。
- no-alpn 禁用Alpn tls tls扩展。
- http2 告诉curl使用http版本2。
https://curl.se/docs/manpage.html#-http2-prior-knowledge“ rel =” nofollow noreferrer“> - http2-prior-knowledge 告诉Curl使用HTTP版本2。

You should use TLS encryption with Application-Layer Protocol Negotiation (ALPN).

What happens?

  1. Client establish network connection to server.
  2. Client sends a request using HTTP/2 protocol.
  3. Server receives the data and expects it to be part of TLS Handshake protocol.
  4. Server has to close the connection because the data does not satisfy TLS protocol.
  5. An io.ErrUnexpectedEOF error is returned because the connection was closed before the response was read.

What needs to be change

The client establishes a connection to the standard HTTPS port (port number is 443), but use net.Dial() function. HTTPS protocol use TLS to secure HTTP connection over the Internet. Therefore, the client have to use tls.Dial() function to establish a connection:

tcpConn, err := tls.Dial("tcp", "clients1.google.com:443", new(tls.Config))

However, the client cannot use an empty TLS configuration. In this particular case, the server supports both protocols: HTTP/1.1 and HTTP/2. By default, the server uses HTTP/1.1 protocol. There are two ways to request the use of HTTP/2 protocol:

The second method is not suitable. The first reason is that http2 package is not intended for this. The second reason is that the server ignores HTTP Upgrade mechanism for the given request.

In order to use the first methods, we need to add "h2" identifier to a list of supported application level protocols (a list of all registered identifiers can be found on IANA website).

conf := & tls.Config {
    NextProtos: []string{"h2"},
}

tcpConn, err := tls.Dial("tcp", "clients1.google.com:443", conf)

Working Code

package main

import (
    "crypto/tls"
    "fmt"
    "net/http"

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

func main() {
    conf := & tls.Config {
        NextProtos: []string{"h2"},
    }
    tcpConn, err := tls.Dial("tcp", "clients1.google.com:443", conf)
    if err != nil {
        panic(err)
    }
    defer tcpConn.Close()

    t := http2.Transport{}
    http2ClientConn, err := t.NewClientConn(tcpConn)
    if err != nil {
        panic(err)
    }

    req, err := http.NewRequest("GET", "https://clients1.google.com/generate_204", nil)
    if err != nil {
        panic(err)
    }

    resp, err := http2ClientConn.RoundTrip(req)
    if err != nil {
        panic(err)
    }

    defer resp.Body.Close()
    fmt.Println(resp.StatusCode)

}

And a slightly modified version.


cURL is a handy tool for checking.

Make an HTTP/2 request:

 $ curl -i --http2 https://clients1.google.com/generate_204
-| HTTP/2 204

Disable Application-Layer Protocol Negotiation (ALPN):

 $ curl -i --http2 --no-alpn https://clients1.google.com/generate_204
-| HTTP/1.1 204 No Content

Send an HTTP/2 request without Application-Layer Protocol Negotiation (ALPN):

 $ curl -i --http2-prior-knowledge --no-alpn https://clients1.google.com/generate_204
-| curl: (52) Empty reply from server

Error 52: The server did not reply anything, which here is considered an error.

Parameter Description
-i Include the HTTP response headers in the output.
-v Makes curl verbose during the operation.
--no-alpn Disable the ALPN TLS extension.
--http2 Tells curl to use HTTP version 2.
--http2-prior-knowledge Tells curl to use HTTP version 2.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文