javascript - 当服务器需要时间来接收消息时,Firefox 会复制大型 websocket 消息
问题描述
我正在尝试做的事情
- 我有一个 Javascript 客户端(在浏览器中),它向 websocket 服务器发送 10 个 1mb 的数据数组(这通常是来自文件的二进制数据,但我试图尽可能简化)
for
客户端在正常循环中尽可能快地发送所有数据- 服务器从 websocket 连接中读取数据,将数据读入内存,然后在继续之前对该数据进行一些处理(在 go 示例中,
time.Sleep
用于表示“处理数据”,Python 版本已经很慢所以我没有t添加睡眠)
重现代码
客户
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报告
解决方案
推荐阅读
- php - PHP 将数组值转换为键
- angular - 角度:LOCATION_INITIALIZED 它是什么,为什么要使用它?
- c# - 从 OPENID 和 SAML 2.0 中选择什么
- javascript - Javascript根据数组的长度和键值修改数组
- wordpress - Wordpress 商店定位器 HTTP403
- php - 搜索错误:选择:内存耗尽 | 狮身人面像搜索
- windows - 如何配置 Windows 性能数据收集器以正确记录 DST?
- laravel - Laravel 在刀片中使用 {!!nl2br(e())!!} 是否安全
- sapui5 - 如何将 XML 片段添加到 XML 视图?
- delphi - 在 Delphi 6 中使用 Indy 8.0.26 的 PUT 命令