如何使用 WebSockets 将多个文件发送到服务器?

Posted

技术标签:

【中文标题】如何使用 WebSockets 将多个文件发送到服务器?【英文标题】:How to send multiple files to server using WebSockets? 【发布时间】:2021-12-31 20:35:24 【问题描述】:

我正在尝试使用 WebSockets 从客户端向 NodeJS 服务器发送多个文件。

要发送一个文件,我目前执行以下操作:

// Client

let upload = document.getElementById('upload')

button.onclick = async function() 
    let file = upload.files[0];
    let byteFile = await getAsByteArray(file);
    socket.send(byteFile);


async function getAsByteArray(file) 
  return new Uint8Array(await readFile(file))


function readFile(file) 
    return new Promise((resolve, reject) => 
        let reader = new FileReader()

        reader.addEventListener("loadend", e => resolve(e.target.result))
        reader.addEventListener("error", reject)

        reader.readAsArrayBuffer(file)
    );

// Server

ws.on('message', function incoming(message) 

    // This returns a buffer which is what I'm looking for when working with a single file.
    console.log(message);
    return;

这适用于一个文件。我可以根据需要使用缓冲区并处理文件。要发送两个文件,我的想法是将每个文件转换为 Uint8Array(就像我对单个文件所做的那样)并像这样推送到数组:

// Client

let filesArray = [];
let files = upload.files;       // Grab uploaded Manifests

for (let file of files) 
    let byteFile = await getAsByteArray(file);
    filesArray.push(byteFile);


socket.send(filesArray);

与处理一个文件的方式相同,服务器为发送的数组返回一个缓冲区;但是,我不确定如何使用它。我需要每个文件成为它们自己的缓冲区才能使用它们。我在这里采取了错误的方法吗?还是我只是错过了一些能够处理每个文件的转换?

【问题讨论】:

试试看。将每个文件作为一条消息发送,就像每个文件一条消息一样。在服务器上,您会看到每个文件都有一个消息事件。 我确定我想多了。我需要同时发送两个文件。发送两条单独的消息将无法完成我的需要。 我不建议通过 webSocket 上传多个文件。我建议您通过 http 上传它们,因为 http 更适合流式传输,并且有更多支持可以帮助您处理错误等......您可以通过 http 分段上传这两个文件。 您缺少的部分是发送元信息:您要发送的文件的名称是什么?数据的 MIME 类型是什么?它是如何编码的?例如,HTTP 具有指定所有这些信息的标头。 【参考方案1】:

在单独的消息中发送每个缓冲区:

button.onclick = async function() 
    upload.files.forEach(file => socket.send(await getAsByteArray(file)));

【讨论】:

【参考方案2】:

这适用于一个文件。

不是真的。除非它应该用于一些非常简单的设置,可能是在一个隔离的(来自互联网的)网络中。

您实际上是向读取它的服务器发送了一个字节序列,它将如何处理它?保存到磁盘?不验证?但是它如何验证一个随机的字节序列,它没有暗示它是什么?其次,它将保存在哪里?以什么名义?您没有发送任何元数据,例如文件名。它应该为它生成一个随机名称吗?用户如何知道这是他的文件?哎呀,因为您甚至不知道是谁发送了该文件(没有身份验证)。最后,安全性如何?我可以打开到您的服务器的 WebSocket 连接并使用任意数据序列向它发送垃圾邮件,从而有效地杀死它吗?您可能需要一些身份验证,但即使有了它,任何用户都可以发送这样的上传垃圾邮件吗?也许您还需要带有超时的令牌(但是您必须考虑您的服务器将如何发布此类令牌)。

我需要每个文件都成为它们自己的缓冲区才能使用它们。

不,你没有。您需要的最低要求是(1)能够从客户端发送带有元数据的文件,以及(2)能够在服务器端读取带有元数据的文件。您很可能还需要一些身份验证机制。通常,您会为此使用经典的 HTTP,我强烈建议您使用它。

如果你想坚持使用 WebSockets,那么你必须自己实现那些已经很完善的机制。所以我会这样做:

(1) 在 WebSocket 之上定义一个自定义协议。每个帧都应该有一个结构,例如前两个字节表示“命令大小”,接下来的 X 个字节(前 2 个字节解释为大小为 16 的 int)命令为字符串。在服务器端,您读取该命令,将其映射到某个处理程序,然后运行适当的操作。该命令应处理的数据是帧剩余字节中的数据。

(2) 设置身份验证。不在此答案的范围内,仅表明它至关重要。我将其放在 (1) 之后,因为您可以为此重用协议。

(3) 每当您要上传文件时:向服务器发送命令“SEND”。在同一帧中,在“SEND”命令放置元数据(文件名、大小、内容类型等)之后,可以将其编码为以长度为前缀的 JSON。然后将文件内容放入缓冲区。

这个解决方案显然应该使用(前面提到的)令牌进行改进。为了获得适当的响应性和并发性,您可能应该将大文件拆分为单独的 WebSocket 框架(这会使设计变得非常复杂)。

无论如何,如您所见,这个话题绝非易事,需要大量经验。它基本上是在重新实现 HTTP 的功能。 再次重申:我强烈建议您使用普通的旧 HTTP。

【讨论】:

以上是关于如何使用 WebSockets 将多个文件发送到服务器?的主要内容,如果未能解决你的问题,请参考以下文章

Websockets 在客户端发送多个事件和多个事件处理程序

如何使用棘轮 websockets 将数据发送到服务器 onload?

如何在烧瓶中发布请求后使用 websockets 向客户端发送警报

多个独立的 websockets 连接

使用Spring STOMP websockets向单个人发送消息

如何从网站向不支持 Websockets 的 MQTT 代理发送消息?