【问题标题】:Golang parse raw HTTP/2 responseGolang 解析原始 HTTP/2 响应
【发布时间】:2020-10-04 19:07:40
【问题描述】:

我有一个特殊情况,我需要将 HTTP/2 响应输出解析为 Go 的 http.Response。响应本身具有默认结构:

$ curl --include https://google.com

HTTP/2 301
location: https://www.google.com/
content-type: text/html; charset=UTF-8
date: Mon, 15 Jun 2020 11:08:39 GMT
expires: Wed, 15 Jul 2020 11:08:39 GMT
cache-control: public, max-age=2592000
server: gws
content-length: 220

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>

状态和身体本身并不重要,这只是一个例子。

http 库具有函数ReadResponse(r *bufio.Reader, req *Request) (*Response, error),这正是我所需要的,但它无法用malformed HTTP version HTTP/2 解析 HTTP/2,但它适用于 HTTP/1.1 和 HTTP/1.0。另外,用http.DefaultClient.Do()请求后,可以看到响应的字段Proto包含HTTP/2.0,这意味着HTTP/2没有问题。

任何想法如何解析此响应?

【问题讨论】:

  • http.ParseHTTPVersion 函数不解析 HTTP/2.replace HTTP/2HTTP/1.1HTTP/2.0
  • 它也不会解析HTTP/2.0,但HTTP/1.1 可以解决问题,在更复杂的响应中不会简单地替换版本吗?
  • 只匹配body前缀为HTTP/2 ,然后替换前7个字节。
  • 是的,我明白了,我只是问这只是前 7 个字节的问题吗?不同的HTTP版本是不是响应格式、解析规则等不一样?
  • FTR:这不是“原始”HTTP/2 响应。 HTTP/2 使用有状态的二进制协议,因此原始响应不是人类可读的,而且通常甚至不是独立的。这是 curl 对模仿 HTTP/1.x 的 HTTP/2 响应的呈现。

标签: http go http2


【解决方案1】:

总结讨论,解析错误的原因是http.ParseHTTPVersion not parse HTTP/2,把前缀7字节换成HTTP/2.0修复,或者提供pr支持net/http解析HTTP/2 .

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "io"
    "net/http"
)

func main() {
    fmt.Println("Hello, playground")
    req, _ := http.NewRequest("GET", "https://google.com", nil)
    {
        resp, err := http.ReadResponse(bufio.NewReader(bytes.NewBuffer(httpbody)), req)
        fmt.Println(resp, err)
        // err is malformed HTTP version "HTTP/2", because http.ParseHTTPVersion not parse "HTTP/2"
    }

    {
        body := bytes.NewBuffer(httpbody)
        prefix := make([]byte, 7)
        n, err := io.ReadFull(body, prefix)
        if err != nil {
            panic("handler err")
        }
        fmt.Println(n, err, string(prefix))
        if string(prefix[:n]) == "HTTP/2 " {
            // fix HTTP/2 proto
            resp, err := http.ReadResponse(bufio.NewReader(io.MultiReader(bytes.NewBufferString("HTTP/2.0 "), body)), req)
            fmt.Println(resp, err)
        } else {
            // other proto
            resp, err := http.ReadResponse(bufio.NewReader(io.MultiReader(bytes.NewBuffer(prefix[:n]), body)), req)
            fmt.Println(resp, err)
        }
    }
}

var httpbody = []byte(`HTTP/2 301
location: https://www.google.com/
content-type: text/html; charset=UTF-8
date: Mon, 15 Jun 2020 11:08:39 GMT
expires: Wed, 15 Jul 2020 11:08:39 GMT
cache-control: public, max-age=2592000
server: gws
content-length: 220

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>`)

输出:

Hello, playground
<nil> malformed HTTP version "HTTP/2"
7 <nil> HTTP/2 
&{301 301 HTTP/2.0 2 0 map[Cache-Control:[public, max-age=2592000] Content-Length:[220] Content-Type:[text/html; charset=UTF-8] Date:[Mon, 15 Jun 2020 11:08:39 GMT] Expires:[Wed, 15 Jul 2020 11:08:39 GMT] Location:[https://www.google.com/] Server:[gws]] 0xc0000902c0 220 [] false false map[] 0xc0000f2000 <nil>} <nil>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-27
    • 2012-02-13
    • 1970-01-01
    • 2011-10-10
    • 1970-01-01
    • 2012-10-26
    • 2011-06-08
    • 1970-01-01
    相关资源
    最近更新 更多