Go的httputil.ReverseProxy不适用于WebSocket流量。 here对此问题进行了详细说明。看起来该修复程序/功能可能已在Go 1.12中发布(请参阅“将其添加到Go1.12里程碑中” here)。
由于修复/功能尚未发布,因此我试图编写自己的反向代理来解决该问题,直到发布为止。在服务器上,我编写了一个简单的gorilla/websocket处理程序,该处理程序将升级连接,然后等待来自客户端的消息。
在我的反向代理服务器上,我根据Go 1.12更改提交here,特别是在reverseproxy.go中的添加,编写了一个反向代理处理程序。在相关部分,这是我的反向代理处理程序的核心:
outreq := r.WithContext(ctx)
if r.ContentLength == 0 {
outreq.Body = nil
}
p.director(outreq)
outreq.Header = copyHeaders(browserHeaders)
setForwardHeader(r.RemoteAddr, outreq)
log.Infof("outreq URL is %+v", outreq.URL)
transport := http.DefaultTransport
res, err := transport.RoundTrip(outreq)
if err != nil {
log.Errorf("RoundTrip(outreq) failed: %s", err)
}
log.Infof("Server response was %+v", res)
if res.StatusCode != http.StatusSwitchingProtocols {
log.Errorf("Did not receive HTTP status 101 switchingn protocols: %d\n", res.StatusCode)
return
}
if !hasUpgradeHeaders(res.Header) {
log.Error("request does not contain upgrade headers")
return
}
backConn, ok := res.Body.(io.ReadWriteCloser)
if !ok {
log.Errorf("internal error: 101 switching protocols response with non-writable body: %v (%T)", res.Body, res.Body)
return
}
当我尝试通过浏览器连接WebSocket时,我得到的是最后一个if语句。类型为io.ReadWriteCloser
的响应正文的类型声明失败。当我记录响应时,我看到以下内容:
Server response was &{Status:101 Switching Protocols StatusCode:101 Proto:HTTP/1.1
ProtoMajor:1 ProtoMinor:1 Header:map[Upgrade:[websocket] Connection:[Upgrade]
Sec-Websocket-Accept:[B1fWETPTtNo0bAHFWkFn2lAm9iw=]] Body:{} ContentLength:0
TransferEncoding:[] Close:false Uncompressed:false
Trailer:map[] Request:0xc000112100 TLS:<nil>}
错误日志输出是这样的:
ERRO[0012] internal error: 101 switching protocols response with non-writable body: {} (http.noBody)
为什么我在响应正文中得到http.noBody
而不是实现io.ReadWriteCloser
接口的东西?如何解决该问题,以便可以继续进行hijack连接并促进浏览器与服务器之间的通信?
我认为我找到了“为什么”问题的答案。 Go的最新版本在net / http包中的transport.go中的persistConn的readLoop函数中不包含以下行:
if resp.isProtocolSwitch() {
resp.Body = newReadWriteCloserBody(pc.br, pc.conn)
}
与当前的here比较。
有任何解决方法的想法吗?