通过 socket.io (JavaScript & FileReader) 上传文件

File uploads through socket.io (JavaScript & FileReader)

我正在创建一个聊天应用程序(在 React Native 中),但目前,我已经在 vanilla JavaScript 中进行了一些测试。服务器是 NodeJS 服务器。

它适用于发送短信,但现在我对发送 photos/videos/audio 文件有一些疑问。我在网上做了很多研究,看看什么是最好的方法。

我想到了使用 FileReader API 并将文件分成块,然后通过 socket.emit()- 函数逐块发送。

到目前为止,这是我的代码(已简化):

请注意,我将创建一个 React Native 应用程序,但现在(为了测试),我刚刚创建了一个带有上传表单的 HTML 文件。

// index.html
// the page where my upload form is

var reader = {};
var file = {};
var sliceSize = 1000 * 1024;
var socket = io('http://localhost:8080');

const startUpload = e => {
    e.preventDefault();
    reader = new FileReader();
    file = $('#file)[0].files[0]
    uploadFile(0)
}

$('#start-upload').on('click', startUpload)

const uploadFile = start => {
    var slice = start + sliceSize + 1;
    var blob = file.slice(start, slice)
    reader.on('loadend', e => {
        if (slice < file.size) {
            socket.emit('message', JSON.stringify({
                fileName: file.name,
                fileType: file.type,
                fileChunk: e.target.result
            })
        } else {
            console.log('Upload completed!')
        }
    })
    reader.readAsDataURl(blob) 
}

// app.js
// my NodeJS server-file

var file;
var files = {};

io.on('connection', socket => {
    console.log('User connected!');

    // when a message is received
    socket.on('message', data => {
        file = JSON.parse(data)
        if (!files[file.fileName]) {
            // this is the first chunk received
            // create a new string
            files[file.fileName] = '';
        }
        // append the binary data
        files[file.fileName] = files[file.fileName] + file.fileChunk;
    })

    // on disconnect
    socket.on('disconnect', () => {
        console.log('User disconnected!');
    })
})

我没有包括任何文件类型检查(我还没有到那个时候),我首先想确保这是正确的做法。

我需要做的事情:

我的问题是:

如果有更好的方法,请告诉我。我不是在要求工作代码示例,只是在好的方向上提供一些指导。

您可以通过 WebSocket 发送原始字节,base64 有 33% 的大小开销。

此外,您不必 JSON.stringify 所有(可能是大)正文并在客户端解析它。

Will I lose some quality

不,底层协议 (TCP) 会按顺序且无损坏地传送数据。

我意识到这个答案晚了几个月,但为了将来参考,您应该考虑使用 socket.io here

的确认选项
  // with acknowledgement
  let message = JSON.stringify({
                fileName: file.name,
                fileType: file.type,
                fileChunk: e.target.result
            })
  socket.emit("message", message, (ack) => {
    // send next chunk...
  });