如何通过 Websocket 发送文件以及附加信息?

use*_*982 7 base64 websocket node.js bson

我正在开发一个 Web 应用程序,用于从管理界面向两台显示器发送图像、视频等。我在 Node.js 中使用 ws 作为服务器端。我已经实现了选择服务器和外部 URL 上可用的图像并将它们发送到客户端,但我还希望能够直接发送从设备中选择的图像和文件输入。我设法使用 base64 来做到这一点,但我认为它的效率很低。

目前,我发送一个字符串化的 JSON 对象,其中包含必须将资源发送到的客户端、资源类型和资源本身,在服务器中解析它并将其发送到适当的客户端。我知道我可以将 Websocket binaryType 设置为 blob 并只发送 File 对象,但是我无法告诉服务器它必须将它发送到哪个客户端。我尝试使用 typeson 和 BSON 来完成此操作,但没有奏效。

还有其他方法可以做到吗?

Mys*_*yst 7

您可以通过 WebSocket 发送原始二进制数据。

这很容易管理。

一种选择是在前面添加一个“魔术字节”(将消息标记为非 JSON 的标识符)。例如,在二进制消息前加上B字符。

服务器所要做的就是在收集二进制数据之前测试第一个字符(如果魔术字节不存在,它可能是正常的 JSON 消息)。

更严肃的实现将在魔术字节之后附加一个标头(即文件名、总长度、发送数据的位置等)。

这允许在断开连接时恢复上传(仅发送未被确认为接收的部分。

在处理之前magic byte,您的服务器需要将数据拆分为,headerbinary_data。但它很容易完成。


小智 6

希望这有助于某人。根据 socket.io 文档,您可以发送字符串、缓冲区或两者混合

在客户端:

function uploadFile(e, socket, to) {
  let file = e.target.files[0];

  if (!file) {
    return
  }
  if (file.size > 10000000) {
    alert('File should be smaller than 1MB')
    return
  }

  var reader = new FileReader();
  var rawData = new ArrayBuffer();

  reader.onload = function (e) {
    rawData = e.target.result;
    socket.emit("send_message", {
      type: 'attachment',
      data: rawData
    } , (result) => {
      alert("Server has received file!")
    });
    alert("the File has been transferred.")
  }

  reader.readAsArrayBuffer(file);
}
Run Code Online (Sandbox Code Playgroud)

在服务器端:

socket.on('send_message', async (data, cb) => {
  if (data.type == 'attachment') {
      console.log('Found binary data')
      cb("Received file successfully.")
      return
    }
// Process other business...
});
Run Code Online (Sandbox Code Playgroud)


Fid*_*ide 5

我正在使用没有 io 的纯 WebSocket,您不能混合内容 - 字符串或二进制。然后我的工作解决方案是这样的:

客户:

    import { serialize } from 'bson';
    import { Buffer } from 'buffer';

    const reader = new FileReader();
    let rawData = new ArrayBuffer();
    ws = new WebSocket(...)
    reader.onload = (e) => {
      rawData = e.target.result;
      const bufferData = Buffer.from(rawData);
      const bsonData = serialize({  // whatever js Object you need
        file: bufferData,
        route: 'TRANSFER',
        action: 'FILE_UPLOAD',
      });
      ws.send(bsonData);
    }
Run Code Online (Sandbox Code Playgroud)

然后在节点服务器端,消息被捕获并解析如下:

        const dataFromClient = deserialize(wsMessage, {promoteBuffers: true}) // edited
        fs.writeFile(
          path.join('../server', 'yourfiles', 'yourfile.txt'),
          dataFromClient.file, // edited
          'binary',
          (err) => {
            console.log('ERROR!!!!', err);
          }
        );
Run Code Online (Sandbox Code Playgroud)

杀手是promoteBuffer反序列化功能中的选项。