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



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

它适用于发送短信,但现在我对发送照片/视频/音频文件有一些疑问。我在网上做了很多关于最好的方法的研究。

我想出了使用 FileReader API 并将文件拆分为块的想法,并通过 socket.emit((-function 逐块发送。

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

请注意,我将创建一个 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!');
})
})

我没有包括对文件类型的任何检查(我还没有达到这一点(,我首先想确保这是正确的做法。

我需要做的事情:

  • 从客户端向服务器发送一条消息(如socket.emit('uploaddone', ...((,以通知服务器上传已完成(服务器可以将完整的文件发送给其他用户(。

我的问题是:

  • 可以通过套接字发送二进制数据块(base64(,还是占用大量带宽?
  • 将它们
  • 分成块时会丢失一些质量(照片/视频/音频文件(吗?

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

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

此外,您不必JSON.stringify所有(也许是大型(主体并在客户端解析它。

我会失去一些质量吗

否,底层协议 (TCP( 按顺序交付数据,且不会损坏。

我意识到这个答案晚了几个月,但仅供将来参考,您应该在这里研究使用确认选项 socket.io

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

最新更新