跨设备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
相关产品推荐
相关产品推荐

