前几天在看一段和 HTTP 有关的代码的时候突然发现了这么一段代码,以前没见过类似的库和代码逻辑,不知道啥意思,所以就顺手搜索了一下,发现了一个挺有意思的东西:hijack。

这是一段接管 HTTP 连接的代码,所谓的接管 HTTP 连接是指这里接管了 HTTP 的 Socket 连接,也就是说 Golang 的内置 HTTP 库和 HTTPServer 库将不会管理这个 Socket 连接的生命周期,这个生命周期已经划给 Hijacker 了,在 Hijacker 的代码注释里面是这么描述的:

听上去很强大啊,不知道它是如何实现的,所以我决定小窥一番。这个看代码的使用应该是需要翻 Golang 内置库中的 HTTP 的实现,然后经过跳转了很多代码之后,我找到了这么一段:

这里的上文是当调用 Hijack 的时候,就会将对应的 conn 设置为 StateHijacked,就进入到这个函数了,在这个函数里面,其实就是将对应的 conn 从管理的 conn 列表中去除:

然后这个 Connection 就被 Http Server 抛弃了,交给你需要的人管理了。

Hijack 的用处

可能乍一看觉得这东西有毛用啊,本来 HTTP 就是 Request-Response 模型的,我还特么没事得接管 Connection 的管理,不是找事做么?是的,通常情况下,如果这么做是没事找事,但是,有的时候不能不这么做啊,例如这里举两个场景来看看。

Grpc Stream

写过一些 Grpc 的同学应该都了解,在 GRPC 中有四种类型的 RPC,同时 GRPC 是构建在 HTTP/2.0 之上的,那么有没有办法可以通过 HTTP/1.1 来支持 GRPC 的 stream rpc 呢?这里其实就可以通过 hijack 的黑科技来实现,将 Client 和 Server 两端进行 hijack 一番,其实就有点类似于在 TCP 之上通信了。

Websocket 管理

Websocket 其实也是有点类似,因为 Websocket 第一阶段走的是普通的 HTTP,后面马上就升级为 Websocket 协议了,所以如果你希望作为中间人操作一些事情的话,那么 hijack 或许是一个很重要的选择。