首页 > 解决方案 > 当服务器需要时间来接收消息时,Firefox 会复制大型 websocket 消息

问题描述

我正在尝试做的事情


重现代码

客户

const ws = new WebSocket('ws://127.0.0.1:8080/');

ws.onopen = async () => {
    for (let i = 0; i < 10; i++) {
        // Create a 1mb array filled with the value of `i`.
        const data = new Uint8Array(1024 * 1024);
        for (let j = 0; j < 1024 * 1024; j++) {
            data[j] = i;
        }
        ws.send(data);
    }
};

服务器(任何一个都会重现问题)

Python:

from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket

class SimpleEcho(WebSocket):
    def handleMessage(self):
        print(self.data[0:10])
    def handleConnected(self):
        print(self.address, 'connected')
    def handleClose(self):
        print(self.address, 'closed')

server = SimpleWebSocketServer('127.0.0.1', 8080, SimpleEcho)
server.serveforever()

戈朗:

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "github.com/gorilla/websocket"
    "net/http"
    "time"
)

func websocketHandler(w http.ResponseWriter, r *http.Request) {
    upgrader := websocket.Upgrader{}
    upgrader.CheckOrigin = func(r *http.Request) bool { return true }
    ws, _ := upgrader.Upgrade(w, r, nil)
    defer ws.Close()

    for i := 0; i < 10; i++ {
        _, fileBytes, _ := ws.ReadMessage()
        fmt.Println(fileBytes[0:10])
        // Represents taking 1 second to process uploaded data.
        time.Sleep(time.Second * 1)
    }
}

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/", websocketHandler).Methods("GET")
    _ = http.ListenAndServe("127.0.0.1:8080", r)
}


期望的行为

来自 javascript 客户端的所有数据都应该在 go 服务器上结束,服务器会为每个数字打印一个接收到的数组,这是一个示例服务器日志,它显示了接收到的每条消息的前 10 个字节:

[0 0 0 0 0 0 0 0 0 0]
[1 1 1 1 1 1 1 1 1 1]
[2 2 2 2 2 2 2 2 2 2]
[3 3 3 3 3 3 3 3 3 3]
[4 4 4 4 4 4 4 4 4 4]
[5 5 5 5 5 5 5 5 5 5]
[6 6 6 6 6 6 6 6 6 6]
[7 7 7 7 7 7 7 7 7 7]
[8 8 8 8 8 8 8 8 8 8]
[9 9 9 9 9 9 9 9 9 9]

这正是我想要的,每个不同的数组只收到一次。


实际发生了什么

就是服务器读取了一些数据,然后服务器再从websocket中读取相同的数据,而不是新的数据。

在下面的服务器日志中,您可以看到它工作正常,直到包含“5”的数据数组连续接收 4 次,然后跳转到接收“8”:

Serving at http://127.0.0.1:8080
[0 0 0 0 0 0 0 0 0 0]
[1 1 1 1 1 1 1 1 1 1]
[2 2 2 2 2 2 2 2 2 2]
[3 3 3 3 3 3 3 3 3 3]
[4 4 4 4 4 4 4 4 4 4]
[5 5 5 5 5 5 5 5 5 5]
[5 5 5 5 5 5 5 5 5 5]
[5 5 5 5 5 5 5 5 5 5]
[5 5 5 5 5 5 5 5 5 5]
[8 8 8 8 8 8 8 8 8 8]

仅当 Javascript 在 Firefox(v82.0 64 位)中运行时才会发生这种情况,如果我在 Chrome 中运行代码,代码将按预期工作

我还在 Firefox 开发者版 (83.0b4) 中进行了测试,并且发生了同样的错误。


奇怪的事情阻止了这个问题

如果time.Sleep调用在 go server 代码中被注释掉,则不会发生重复。

python 版本在不休眠的情况下处理请求本质上很慢(因此没有调用 sleep 来表示处理数据),因此如果更快地接收 websocket 消息停止复制,则无法在 Python 服务器上进行测试。

这让我相信这个问题可能与时间有关?

如果在 Javascript 中将 2 个语句替换为预先计算的变量,则不会发生重复1024 * 1024 ,例如

const ws = // websocket
const dataSize = 1024 * 1024;

// rest of code up to:

        const data = new Uint8Array(dataSize);
        for (let j = 0; j < dataSize; j++) {

我不知道为什么会发生这种情况,我开始怀疑这是 Firefox 中的错误。

任何帮助,将不胜感激。

谢谢。

编辑:

看起来这绝对是一个 Firefox 错误,并且这里已经有一个 bugzilla报告

标签: javascriptdebuggingfirefoxbrowserwebsocket

解决方案


推荐阅读