You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨设备React客户端通过WebSocket传输图片时连接中断问题排查

跨设备React客户端通过Node.js WebSocket传输图片的问题

我正在尝试通过Node.js/WebSocket服务器,在两台不同设备的React.js客户端之间传输图片。目前采用将图片转为Base64发送至服务器的方案,但代码执行到client.send()时,WebSocket连接会意外断开。

初始客户端代码

handleFileSelection = (event) => {
    var file = event.target.files[0];
    console.log(file);
    const reader = new FileReader();

    reader.onloadend = () => {
      // Convert the image file to base64-encoded string
      const base64Image = reader.result;
      console.log(base64Image);
      this.setState({ selectedImage: base64Image });

      // Send the base64-encoded image to the server
      client.send(JSON.stringify({
        type: "file selection",
        selectedImage: base64Image,
        boundingBoxes: []
      }));
    }

    reader.readAsDataURL(file);
  }

  renderUploadPhotoButton = () => {
    return (
      <button>
        <label htmlFor='fileUpload'>
          <input
            type="file"
            id='fileUpload'
            hidden
            onChange={(event) => this.handleFileSelection(event)}
          />
          Upload Photo
        </label>
      </button>
    )
  }

componentDidMount() {
    client.onmessage = (message) => {
      const dataFromServer = JSON.parse(message.data);
      console.log('got reply! ', dataFromServer);
      if (dataFromServer.type === "file selection") {
        this.setState({ 
          selectedImage: dataFromServer.selectedImage,
          boundingBoxes: dataFromServer.boundingBoxes })
      } 
    };

初始服务器代码

wsServer.on('request', function (request) {
    var userID = getUniqueID();
    console.log((new Date()) + ' Recieved a new connection from orgin ' + request.origin + ".");

    const connection = request.accept(null, request.origin);
    clients[userID] = connection;
    console.log('connected: ' + userID + ' in ' + Object.getOwnPropertyNames(clients));

    connection.on('message', function(message) {
      if (message.type === 'utf8') {
        console.log('Received Message: ', message.utf8Data);
  
        // broadcasting message to all connected clients
        for(key in clients) {
          clients[key].sendUTF(message.utf8Data);
          console.log('sent Message to: ', clients[key]);
        }
      }
    })
  });

目前仅文件上传功能正常,急需解决跨设备传输的问题。


最初本地可行的方案(跨设备失效)

以下代码仅在两个客户端实例运行于同一设备时可用,跨设备传输时失效:

handleFileSelection = (event) => {
    var file = URL.createObjectURL(event.target.files[0])
    console.log(file);
    this.setState({ selectedImage: file });

    client.send(JSON.stringify({
      type: "file selection",
      selectedImage: file,
      boundingBoxes: []
    }));
  }

componentDidMount() {
    client.onmessage = (message) => {
      const dataFromServer = JSON.parse(message.data);
      console.log('got reply! ', dataFromServer);
      if (dataFromServer.type === "file selection") {
        this.setState({ 
          selectedImage: dataFromServer.selectedImage,
          boundingBoxes: dataFromServer.boundingBoxes })
      } 
    };

Blob传输尝试的问题

猜测问题与Base64文件大小有关,尝试发送Blob同样出现连接中断问题:

客户端代码

handleFileSelection = (event) => {
    const file = event.target.files[0];
    const reader = new FileReader();
  
    reader.onloadend = () => {
      const arrayBuffer = reader.result;
      const blob = new Blob([arrayBuffer]);
      console.log(blob);
  
      client.send(blob);
    };
  
    reader.readAsArrayBuffer(file);
  };

client.onmessage = (message) => {
      if (message instanceof ArrayBuffer) {
        console.log(dataFromServer);
        const blobUrl = URL.createObjectURL(dataFromServer);
        this.setState({ 
          selectedImage: blobUrl,
          boundingBoxes: [] })
      }
}

新增服务器代码

} else if (message.type === 'binary') {
        const binaryData = message.binaryData;

        // broadcasting binary data to all connected clients
        for (key in clients) {
          for (const key in clients) {
            clients[key].sendBytes(binaryData);
            console.log('Sent Binary Data to: ', clients[key]);
        }
        }
    }

若将Blob放入JSON中发送,消息可送达但Blob会变为空对象:

client.send(JSON.stringify({
        type: "file selection",
        blob: blob,
        boundingBoxes: []
      }));

分块传输的尝试与当前状态

确认为文件大小问题,尝试将Base64字符串分块发送后,消息可发送、接收并显示,但仅一端能重组完整图片,原因不明。

修改后的客户端代码

reader.onloadend = () => {
      // Convert the image file to base64-encoded string
      const base64Image = reader.result;
      console.log(base64Image);
      this.setState({ selectedImage: base64Image });
  
      // Split the base64 string into chunks
      const chunkSize = 1024; // Adjust the chunk size as needed
      const totalChunks = Math.ceil(base64Image.length / chunkSize);
  
      // Send each chunk to the server
      for (let i = 0; i <= totalChunks; i++) {
        const chunk = base64Image.substr(i * chunkSize, chunkSize);
        client.send(JSON.stringify({
          type: "file chunk",
          chunk,
          chunkIndex: i,
          totalChunks
        }));
      }
    };
  
    reader.readAsDataURL(file);
  };

componentDidMount() {
    client.onopen = () => {
      console.log('WebSocket Client Connected');
    };
    client.onmessage = (message) => {
        const dataFromServer = JSON.parse(message.data);
        if (dataFromServer.type === "file chunk") {
          const { chunk, chunkIndex, totalChunks } = dataFromServer;
          console.log('got chunk! ', chunkIndex, ' out of ', totalChunks);
      
          // Store the received chunk
          this.updateReceivedChunks(chunkIndex, chunk);

          // Check if all chunks have been received
          if (chunkIndex === totalChunks-1) {
            console.log('Recieved all image chunks');
            // Concatenate the chunks to reconstruct the base64 image
            const base64Image = this.state.receivedChunks.join('');

            // Handle the complete base64 image here
            console.log("Reassembled incoming image chunks. ", base64Image);
            this.setState({ 
              selectedImage: base64Image,
              boundingBoxes: [] })

            // Clear the received chunks array for future use
            this.setState({ receivedChunks: [] });
          }
        }
    };
    
  }

  updateReceivedChunks = (chunkIndex, chunk) => {
    this.setState((prevState) => {
      const updatedChunks = [...prevState.receivedChunks];
      updatedChunks[chunkIndex] = chunk;
      return { receivedChunks: updatedChunks };
    });
  };

目前将重组条件从recievedChunks.length === totalChunks改为chunkIndex === totalChunks-1后,问题似乎已解决,但不确定具体原因,担心后续复现。


内容的提问来源于stack exchange,提问作者Rfritz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 09:57:03