nodejs二进制websocket mimetype处理

nodejs binary websocket mimetype handling

本文关键字:处理 mimetype websocket 二进制 nodejs      更新时间:2023-09-26

我不能100%确定,但从我通过websocket发送blob(二进制数据)时读取的内容来看,blob不包含任何文件信息。(此外,官方规范规定wesockets只发送原始二进制文件)

  1. 文件大小
  2. mimetype
  3. 用户信息(稍后解释)

我正在使用https://github.com/websockets/ws

测试:

直接从输入文件发送blob。

ws.send(this.files[0]) //this should already contain the info

使用本地javascript api从文件创建一个新的blob,设置正确的mimetype。

ws.send(new Blob([this.files[0]],{type:this.files[0].type})); //also this

在两侧,您都只能获得有效的blob,而没有任何其他信息。

是否可以附加一个4kb预定义的json数据,该数据也转换为二进制文件,其中包含mimetype和filesize等重要信息,然后在需要的时候把4kb分开

{"mime":"txt/plain","size":345}____________ 4KB_REST_OF_THE_BINARY

ws.send({"mime":"txt'/plain","size":345})
ws.send(this.files[0])

即使第一个是有史以来最糟糕的解决方案,它也允许我一次性发送所有内容。

第二个有一个大问题:

这是一个聊天,允许发送文件,如文件,图像,音乐视频。

在发送二进制数据之前,我可以在发送文件/用户信息时编写某种握手系统。

但是

如果另一个人也发送了一个文件,因为它是异步的,那么握手系统就没有机会确定哪个文件适合正确的用户和mimetype。

那么,如何在多用户异步环境中正确发送二进制文件呢

我知道我可以转换到base64,但那要大30%。

顺便说一句。对苹果感到非常失望。。。虽然chrome可以正确显示每个二进制数据,但我的ios设备无法处理blob,只有图像会以blob或base64格式显示,甚至不是一个简单的txt文件。基本上只有<img>标签可以读取动态文件。

一切如何运作(现在):

  1. 用户发送文件
  2. nodejs获取二进制数据,以及用户信息。。。但不是mimetype、filename、size
  3. nodejs向所有用户广播原始二进制文件。(无法指定用户和文件信息)
  4. 客户端创建了一个bloburl(谁发送的?XD)

编辑

我现在有什么:

客户端1(发送文件)CHROME

fileInput.addEventListener('change',function(e){
 var file=this.files[0];
 ws.send(new Blob([file],{
  type:file.type //<- SET MIMETYPE
 }));
 //file.size
},false);

注意:file已经是blob。。。但这就是通常创建指定mimetype的新blob的方式。

服务器(向其他客户端广播二进制数据)NODEJS

aaaaaa和mimetype不见了

ws.addListener('message',function(binary){
 var b=0,c=wss.clients.length;
 while(b<c){
  wss.clients[b++].send(binary)
 }
});

客户端2(接收二进制)CHROME

ws.addEventListener('message',function(msg){
 var blob=new Blob([msg.data],{
      type:'application/octet-stream' //<- LOST
     });
 var file=window.URL.createObjectURL(blob);
},false);

注意:m.data已经是blob。。。但这就是通常创建一个新blob的方式,指定mimetype开关丢失。

客户端2中,我需要mimetype,当然我也需要关于用户的信息,这些信息可以从客户机1服务器检索(不是一个好的选择)。。。

你有点运气不好,因为Node不支持Blob接口,所以你用Node以二进制形式发送或接收的任何数据都只是二进制的。你必须有一些知道如何解释Blob对象的东西。

这里有一个想法,让我知道这是否有效。通过阅读websockets'ws的文档,它表示支持发送和接收ArrayBuffers。这意味着您可以使用TypedArrays。

这就是它变得令人讨厌的地方。在每个TypedArray的开头设置一个特定的固定n字节数,以表示utf8中编码的mime类型或其他类型,而TypedArray的其余部分包含文件的字节。

我建议使用UInt8Array,因为utf8字符有8位长,这样编码时您的文本可能是可读的。至于文件位,你可能只会把它们写在某个地方,并在上面加上一个结尾

另外请注意,无论是从节点还是在浏览器中,这种解释方法都可以双向工作。

这个解决方案实际上只是类型转换的一种形式,您可能会得到一些意想不到的结果。mime类型字段的固定长度至关重要。

在这里进行了说明。复制、粘贴、将图像文件设置为所需的任何内容,然后运行该操作。你会看到我设置的哑剧类型弹出。

var fs = require('fs');

//https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer
function toUint8Array(buffer) {
  var ab = new ArrayBuffer(buffer.length);
  var array = new Uint8Array(ab);
  for (var i = 0; i < buffer.length; ++i) {
    array[i] = buffer[i];
  }
  return array;
}
//data is a raw Buffer object
fs.readFile('./ducklings.png', function (err, data) {
  var mime = new Buffer('image/png');
  var allBuffed = Buffer.concat([mime, data]);
  var array = toUint8Array(allBuffed);
  var mimeBytes = array.subarray(0,9); //number of characters in mime Buffer
  console.log(String.fromCharCode.apply(null, mimeBytes));
});

以下是您在客户端的操作方法:

解决方案A:获取包裹

获取缓冲区,用于浏览器的Node的buffer API的实现。连接字节缓冲区的解决方案将与以前完全一样工作。您可以附加像To:和what not这样的字段。我相信,为了更好地为客户服务,你格式化标题的方式将是一个不断发展的过程。

解决方案B:旧学校

步骤1:将Blob转换为ArrayBuffer

注意:如何将字符串转换为ArrayBuffer

var fr = new FileReader();
fr.addEventListener('loadend', function () {
//Asynchronous action in part 2.
  var message = concatenateBuffers(headerStringAsBuffer, fr.result);
  ws.send(message);
});
fr.readAsArrayBuffer(blob);

第2步:连接阵列缓冲区

function concatenateBuffers(buffA, buffB) {
  var byteLength = buffA.byteLength + buffB.byteLength;
  var resultBuffer = new ArrayBuffer(byteLength);
  //wrap ArrayBuffer in a typedArray/view
  var resultView = new Uint8Array(resultBuffer);
  var viewA = new Uint8Array(resultBuffer);
  var viewB = new Uint8Array(resultBuffer);
  //Copy 8 bit integers AKA Bytes
  resultView.set(viewA);
  resultView.set(viewB, viewA.byteLength);
  return resultView.buffer
}

第3步:接收并重新发送

我不打算重复如何将连接的String字节转换回字符串,因为我在服务器示例中已经做过了,但将文件字节转换为mime类型的blob相当简单。

new Blob(buffer.slice(offset, buffer.byteLength), {type: mimetype});

robnyman的Gist进一步详细介绍了如何使用通过XHR传输的图像,将其放入本地存储,并在页面上的图像标签中使用。

我喜欢@Breedly的想法,即准备一个固定长度的字节数组来指示ArrayBuffer的mime类型,所以我创建了这个npm包,我在处理websocket时使用它,但其他人可能会觉得它很有用。

示例用法

const {
  arrayBufferWithMime,
  arrayBufferMimeDecouple
} = require('arraybuffer-mime')
// some image array buffer
const uint8 = new Uint8Array(1)
uint8[0] = 1
const ab = uint8.buffer
const mime = 'image/png'
const abWithMime = arrayBufferWithMime(ab, mime)
const {mime, arrayBuffer} = arrayBufferMimeDecouple(abWithMime)
console.log(mime) // "image/png"
console.log(arrayBuffer) // ArrayBuffer