Go中解码HTTP/2帧Header/Data:如何解析头部块片段获取请求信息
如何解码HTTP/2 HEADERS帧的Block Fragment
嘿,我来帮你搞定这个问题!你拿到的这个block fragment其实是经过HPACK压缩的HTTP头部块——HTTP/2就是用这个算法来压缩请求/响应头部,减少传输体积的,所以直接转ASCII肯定看不懂,得先解码才行。
核心原理
HTTP/2的HEADERS帧里的HeaderBlockFragment是HPACK格式的二进制数据,它通过静态字典、动态字典和哈夫曼编码来压缩HTTP头部字段。要获取请求的方法、路径等信息,必须用HPACK解码器把它还原成键值对形式的HTTP头部。
改造你的Go代码
你可以用Go官方提供的golang.org/x/net/http2/hpack包来完成解码,下面是整合到你原有代码里的示例:
package main import ( "encoding/hex" "fmt" "net" "golang.org/x/net/http2" "golang.org/x/net/http2/hpack" ) func main() { // 假设你已经建立好conn连接并处理了序言和SETTINGS帧 framer := http2.NewFramer(conn, conn) frame, err := framer.ReadFrame() if err != nil { panic(err) } fmt.Printf("fh type: %s\n", frame.Header().Type) fmt.Printf("fh type: %d\n", frame.Header().Type) fmt.Printf("fh flag: %d\n", frame.Header().Flags) fmt.Printf("fh length: %d\n", frame.Header().Length) fmt.Printf("fh streamid: %d\n", frame.Header().StreamID) headersframe, ok := frame.(*http2.HeadersFrame) if !ok { panic("不是HEADERS帧") } fmt.Printf("stream ended? %v\n", headersframe.StreamEnded()) fmt.Printf("block fragment: %x\n", headersframe.HeaderBlockFragment()) // --- 新增HPACK解码部分 --- fragmentBytes := headersframe.HeaderBlockFragment() // 创建HPACK解码器,4096是初始的头部表大小,nil表示不追踪动态表(如果是连续解码多帧建议复用解码器) decoder := hpack.NewDecoder(4096, nil) decodedHeaders, err := decoder.DecodeFull(fragmentBytes) if err != nil { panic(err) } // 打印解码后的头部信息 fmt.Println("\n解码后的HTTP请求头部:") for _, header := range decodedHeaders { fmt.Printf("* %s: %s\n", header.Name, header.Value) } }
你当前输出的解码结果
针对你给出的block fragment: 828487418a089d5c0b8170dc6c4d8b7a8825b650c3abb6f2e053032a2f2a,解码后应该会得到类似这样的结果:
* :method: GET * :scheme: https * :authority: 127.0.0.1:8000 * :path: / * user-agent: curl/xxx.xxx.xxx * accept: */*
这些就是你要找的请求方法、协议、URL路径等核心信息啦!
小提示
如果需要连续解码多个HTTP/2帧的头部块,建议复用同一个HPACK解码器,因为它会维护动态表状态,这样解码出来的结果才准确。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

