刷新浏览器后,WebSocket客户端的onmessage事件无法正常工作。

huangapple go评论93阅读模式
英文:

websocket client onmessage broken after refreshing browser

问题

我有一个使用github.com/gorilla/websocket包编写的go语言的Websocket服务器。

服务器有两个循环,用于接收和发送消息。HTTP处理程序的实现如下所示:

upgrader, errChan := websocket.Upgrader{}, make(chan error)

ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
    http.Error(w, err.Error(), http.StatusInternalServerError)
    return
}

// 处理传入的消息
go func() { 
    for {
        message := Message{}
        if err := ws.ReadJSON(&message); err != nil {
            errChan <- err
        }
        handleMessage(message)
    }
}()

// 处理传出的消息
go func() { 
    for {
        message := <-global.outgoingMessage
        if err = ws.WriteMessage(websocket.TextMessage, message); err != nil {
            errChan <- err
        }
    }
}()

err = <-errChan
ws.Close()

客户端应用程序使用React,并将消息用作状态。当应用程序启动时,建立WebSocket连接,并且onopen回调函数触发对初始数据的请求。响应由onmessage捕获,用于应用程序状态。实现如下所示:

var ws = new WebSocket("ws://localhost:8080/app");

ws.onerror = function(err) {
    alert(err);
}
ws.onmessage = function(m) {
    var state = JSON.parse(m.data);
    global.app.setState(state);
}
ws.onopen = function() { 
    ws.send('{"type":"init"}');
}

在这种设置下,我注意到第一次启动应用程序并浏览到页面时一切正常。一旦刷新浏览器,它就不再工作。我可以调用ws.send('{"type":"init"}')并看到服务器发送的响应,但onmessage回调函数不会触发。在多次尝试调用ws.send('{"type":"init"}')后,onmessage最终会被调用一次,并加载应用程序状态。如果我关闭并重新启动应用程序,相同的行为会发生。

你有什么想法?

英文:

I have a Websocket server written in go with package github.com/gorilla/websocket.

The server has 2 loops for receiving and sending messages. The implementation of the http handler looks like the following:

upgrader, errChan := websocket.Upgrader{}, make(chan error)

ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
	http.Error(w, err.Error(), http.StatusInternalServerError)
	return
}

// incoming messages

go func() { 
	for {
		message := Message{}
		if err := ws.ReadJSON(&amp;message); err != nil {
			errChan &lt;- err
		}
        handleMessage(message)
	}
}()

// outgoing messages 

go func() { 
	for {
		message := &lt;-global.outgoingMessage
		if err = ws.WriteMessage(websocket.TextMessage, message); err != nil {
            errChan &lt;- err
        }
	}
}()

err = &lt;- errChan
ws.Close()

The client application uses React and the app uses the message to as a state. When the app is launched, the websocket connection is established and the onopen callback fires a request for the initial data. The response is caught by onmessage which is used for the app state. The implementation looks like the following:

var ws = new WebSocket(&quot;ws://localhost:8080/app&quot;)

ws.onerror = function(err) {
	alert(err)
}
ws.onmessage = function(m) {
	var state = JSON.parse(m.data)
	global.app.setState(state) 
}
ws.onopen = function() { 
	ws.send(&#39;{&quot;type&quot;:&quot;init&quot;}&#39;)
}

With this setup, what I've been noticing is the first time I fire up the app and browse to the page everything works fine. Once I refresh the browser, it no longer works. I can call ws.send(&#39;{&quot;type&quot;:&quot;init&quot;}&#39;) and see the response sent by the server but the onmessage callback doesn't get fired. After several more tries of calling ws.send(&#39;{&quot;type&quot;:&quot;init&quot;}&#39;) the onmessage eventually gets called once and the app state gets loaded. If I kill and restart the app, the same behaviour occurs.

Thoughts?

答案1

得分: 0

看起来所有的输出goroutine都从单个通道global.outgoingMessage接收消息,而且发送到该通道的消息不足以满足所有正在运行的输出goroutine的需求。

如果应用程序的意图是向所有连接的客户端广播消息,那么我建议按照Gorilla聊天示例中的hub模式进行操作。

另外:该应用程序存在goroutine泄漏问题。可以参考这个问题来了解解释。

英文:

It looks like all output goroutines receive from the single channel global.outgoingMessage and that insufficient messages are sent to this channel to satisfy all running output goroutines.

If the intent of the application is to broadcast to all connected clients, then I suggest following the hub pattern in the Gorilla chat example.

Aside: The application leaks goroutines. See this question for an explanation.

huangapple
  • 本文由 发表于 2016年12月1日 12:48:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/40902841.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定