如何通过socket.io将图片发送到服务器?

7
我为此一直苦苦思索,但始终找不到正确的解决方案。我想通过socket.io emit上传图像到服务器,并稍后将它们保存到MongoDB数据库中。我该怎么做呢?我看到有人使用base64编码来实现,但我无法弄清楚它究竟是如何工作的。本网站上有关于通过socket.io从服务器发送图像到客户端的其他问题,但没有关于这个问题的。非常感谢您的帮助。<3
目标:使用 socket.emit('image', someimagefile) 或类似方法上传图像到服务器。
如果可能的话,我也很感激您提供一种将图像发送给客户端的相似方式。

6
不要使用Base64...它是无意义的。你所做的只是增加了33%的开销,浪费了CPU和内存使用,却没有任何好处。Web Sockets和Socket.IO支持二进制传输。此外,为什么要通过socket.IO发送它呢?正常的HTTP请求也可以很好地工作。另外,虽然你可以将二进制数据塞到MongoDB数据库中,但这很少是最佳解决方案。最好只需将资产存储在磁盘上,以便以后可以使用普通的CDN等进行服务。 - Brad
3个回答

10

就像您所提到的那样,您可以使用FileReader.readAsDataURL将图像转换为base64编码的字符串,并将其发送到服务器解码:

document.getElementById('file').addEventListener('change', function() {

  const reader = new FileReader();
  reader.onload = function() {
    const base64 = this.result.replace(/.*base64,/, '');
    socket.emit('image', base64);
  };
  reader.readAsDataURL(this.files[0]);

}, false);
socket.on('image', async image => {
    const buffer = Buffer.from(image, 'base64');
    await fs.writeFile('/tmp/image', buffer).catch(console.error); // fs.promises
});

或者更好地使用FileReader.readAsArrayBuffer来获取一个字节的数组,您将发送该数组到服务器。

document.getElementById('file').addEventListener('change', function() {

  const reader = new FileReader();
  reader.onload = function() {
    const bytes = new Uint8Array(this.result);
    socket.emit('image', bytes);
  };
  reader.readAsArrayBuffer(this.files[0]);

}, false);
socket.on('image', async image => {
    // image is an array of bytes
    const buffer = Buffer.from(image);
    await fs.writeFile('/tmp/image', buffer).catch(console.error); // fs.promises
});
从服务器接收数据:
// Server side
socket.emit('image', image.toString('base64')); // image should be a buffer
// Client side
socket.on('image', image => {
    // create image with
    const img = new Image();
    // change image type to whatever you use, or detect it in the backend 
    // and send it if you support multiple extensions
    img.src = `data:image/jpg;base64,${image}`; 
    // Insert it into the DOM
});

1

Base64可以使用,但需要注意的一点是套接字缓冲区大小限制为1 MB。(根据文档,可以增加此限制)。

因此,如果文件大小很大,最好使用类似于socket.io-stream的流来传输。


0

我不知道是否还有人在寻找它,但我已经成功地通过socket.io发送媒体...这是代码:

// sending media from client side
$("#send_media").change(function (e) {
  var data = e.originalEvent.target.files[0];
  var reader = new FileReader();
  reader.onload = function (evt) {
    var msg = {};
    msg.file = evt.target.result;
    msg.fileName = data.name;
    socket.emit("base64 file", msg);
    console.log(msg)
  };
  reader.readAsDataURL(data);
});
   
// showing media to ui 
socket.on("base64 image", (msg) => {
  console.log("as", msg);
  $(".messages")
    .append(`<img src=${msg.file} alt="Red dot" />`);

  scrollToBottom();
});

// sending media from server side
    socket.on("base64 file", function (msg) {
      console.log("received base64 file from server: " + msg.fileName);
      socket.username = msg.username;
      io.to(roomId).emit('base64 image', //exclude sender
      // io.sockets.emit(
      //   "base64 file", //include sender

        {
          file: msg.file,
          fileName: msg.fileName,
        }
      );
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接