发送连接升级后,如何在golang中将客户端http连接升级到websockets
Posted
技术标签:
【中文标题】发送连接升级后,如何在golang中将客户端http连接升级到websockets【英文标题】:How can I upgrade a client http connection to websockets in golang after sending the connection upgrade 【发布时间】:2019-04-05 13:24:10 【问题描述】:我需要一个可以从 http get 响应升级到 websocket 连接的 golang 客户端。
我有一个可以工作的 JS 客户端,并且我看到了直接的 ws 客户端连接,但我必须从 http 升级。我曾尝试寻找其他 3GL 解决方案(Java、C#、Python),但我需要能够在 Go 中实现升级。我已经看到 Dart 分离套接字并从中创建一个 websocket。
WebSocket.fromUpgradedSocket
我注意到Client does not support Hijack,但讨论并没有让我有所收获。 我正在使用 github.com/gorilla/websocket 但如果有帮助可以更改。
服务器:
func main()
srv := Srv
count = 0
http.HandleFunc("/", srv.handleRoot)
http.HandleFunc("/ws", srv.handleWs)
log.Fatal(http.ListenAndServe(":5002", nil))
func (tool *Srv) handleRoot(w http.ResponseWriter, r *http.Request)
webSocketKey := hdr.Get("Sec-WebSocket-Key")
log.Printf("Socket key = '%v'", webSocketKey)
secWsAccept := computeAcceptKey(webSocketKey)
log.Printf("Accept = '%v'", secWsAccept)
w.Header().Add("sec-websocket-accept", secWsAccept)
w.Header().Add("upgrade", "websockt")
w.Header().Add("connection", "upgrade")
w.WriteHeader(101)
func (tool *Srv) handleWs(w http.ResponseWriter, r *http.Request)
var upgrader = websocket.Upgrader
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil
log.Fatalf("Websocket fatal error. %v", err)
tool.conn = conn
go tool.serviceWsRequests()
func (tool *Srv) serviceWsRequests()
for
log.Printf("starting ws")
req := request
err := tool.conn.ReadJSON(&req)
if err != nil
log.Printf("Failed to decode ws message. %v", err)
break
fmt.Printf("Got request. %v\n", req)
if req.Method == "ping"
fmt.Printf("Param=%v\n", req.Parameters)
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
func computeAcceptKey(challengeKey string) string
h := sha1.New()
h.Write([]byte(challengeKey))
h.Write(keyGUID)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
客户:
func main()
tr := &http.Transport
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
client := &http.Client
Transport: tr,
// Do NOT follow redirects
CheckRedirect: func(req *http.Request, via []*http.Request) error
return http.ErrUseLastResponse
,
wsKey, err := generateKey()
if err != nil
log.Printf("Cannot generate challenge key %v", err)
// Get request for ws upgrade.
req, err := http.NewRequest("GET", "http://localhost:5002", nil)
req.Header.Add("Connection", "Upgrade")
req.Header.Add("Upgrade", "websocket")
req.Header.Add("Sec-WebSocket-Version", "13")
req.Header.Add("Sec-WebSocket-Key", wsKey)
log.Printf("ws key '%v'", wsKey)
resp, err := client.Do(req)
if err != nil
log.Printf("Get error %v", err)
defer func()
if resp != nil
err = resp.Body.Close()
()
log.Printf("Status='%v', proto='%v'", resp.Status, resp.Proto)
body, err := ioutil.ReadAll(resp.Body)
hdr := resp.Header
for k, v := range hdr
log.Printf("%v : %v", k, v)
log.Printf("Body = %v", string(body))
resp, err = http.Get("ws://localhost:5002/ws")
if err != nil
log.Printf("Error '%v'", err)
func generateKey() (string, error)
p := make([]byte, 16)
if _, err := io.ReadFull(rand.Reader, p); err != nil
return "", err
return base64.StdEncoding.EncodeToString(p), nil
var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
func computeAcceptKey(challengeKey string) string
h := sha1.New()
h.Write([]byte(challengeKey))
h.Write(keyGUID)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
我收到一个错误
Error 'Get ws://localhost:5002/ws: unsupported protocol scheme "ws"'
这并不让我感到惊讶,因为我还没有升级连接。 那么如何在 Go 中进行升级呢?
【问题讨论】:
【参考方案1】:使用Gorilla client拨打websocket连接:
func main()
c, _ , err := websocket.DefaultDialer.Dial("ws://localhost:5002/ws", nil)
if err != nil
// handle error
defer c.Close()
// do something with c, a *websocket.Conn
Dial 方法向服务器发出 GET 请求升级到 WebSocket 协议。成功完成升级后,Dial 会返回 *websocket.Conn
。
【讨论】:
@Compree Gorilla 客户端向服务器发出 GET 请求,请求升级到 WebSocket 协议。如果您必须使用从 net/http 包返回的 http.Response,请编辑问题以解释原因。在 Go 中拨入服务器的常用方法是使用现有的客户端库之一(Gorilla、x/net/websocket)。 谢谢。 Gorilla 提供的 HTTP 升级就足够了。我过于复杂了,以为我必须自己处理 HTTP 升级。以上是关于发送连接升级后,如何在golang中将客户端http连接升级到websockets的主要内容,如果未能解决你的问题,请参考以下文章