nodejs二进制websocket mimetype处理

我不是100%确定,但从我读的时候,我发送blob(二进制数据)通过websocket,blob不包含任何文件信息。 (官方的规格说明wesockets只发送原始二进制文件)

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

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

testing:

直接从input文件发送blob。

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

用文件中的原生javascript api创build一个新的blob,设置正确的mimetype。

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

双方都可以得到没有任何其他信息的有效的blob。

有没有可能追加我们说一个4kb的预定义json数据转换成二进制包含重要的信息,如MIMEtypes和文件大小,然后在需要时分裂4kb?

{ “MIME”: “TXT /纯”, “大小”:345} ____________ 4KB_REST_OF_THE_BINARY

要么

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

即使第一个是有史以来最糟糕的解决scheme ,它也可以让我一次发送一切。

第二个有一个大问题:

这是一个聊天,可以发送文件,图像,音乐video等文件。

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

如果另一个人也发送一个文件,因为它是asynchronous的,握手系统没有机会确定哪个文件是正确的用户和mimetype。

那么如何在多用户asynchronous环境下正确发送二进制文件呢?

我知道我可以转换成base64,但是这个30%更大。

顺便说一句。 完全失望与苹果 …虽然铬显示每个二进制数据正常,我的iOS设备无法处理blob的,只有图像将显示blob或base64格式,甚至不是一个简单的txt文件。 基本上只有一个<img>标签可以读取dynamic文件。

一切如何运作(现在):

  1. 用户发送一个文件
  2. nodejs获取二进制数据,也是用户信息…但不是mimetype,文件名,大小。
  3. nodejs将原始二进制文件广播给所有用户(不能指定用户和文件信息)
  4. 客户端创build一个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 …但是这是你通常会创build一个指定mimetype的新blob。

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

aaaaaand 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了…但是这通常会创build一个新的blob来指定mimetype女巫丢失。

客户端2我需要mimetype,自然我也需要有关用户的信息,这可以从客户端1服务器 (不是一个好的select)检索…

由于Node不支持Blob接口,因此您在Binary with Node中发送或接收的任何数据都是Binary。 你将不得不有一些知道如何解释一个Blob对象。

这是一个想法,让我知道这是否工作。 阅读websockets\ws文档说它支持发送和接收ArrayBuffers 。 这意味着你可以使用TypedArrays 。

这里是讨厌的地方。 在每个TypedArray的开头设置一定的固定 n个字节来表示用utf8编码的MIMEtypes,或者你有什么,其余的TypedArray包含文件的字节。

我build议使用UInt8Array因为utf8字符长度为8位,并且在编码时可能会读取文本。 至于文件位,你可能最终会把这些文件写下来,然后附加一个结尾。

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

这个解决scheme实际上只是一种types转换的forms,您可能会得到一些意外的结果。 你的mimetypes字段的固定长度是至关重要的。

这里说明。 复制,粘贴,设置图像文件到任何你想要的,然后运行。 你会看到我popup的MIMEtypes。

 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)); }); 

以下是你如何在客户端做到这一点:

解决schemeA:获得一个包装

获取缓冲区 ,用于浏览器的Node的缓冲区API的实现。 连接字节缓冲区的解决scheme将像以前一样工作。 你可以追加To:这样的字段,还有什么不是。 为了更好地为您的客户提供服务,您devise标题的方式将是一个不断演变的过程,我相信。

解决schemeB:老学校

第1步:将您的Blob转换为ArrayBuffer

备注: 如何将string转换为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步:连接ArrayBuffers

 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字节转换回string,因为我已经在服务器示例中完成了它,但是将文件字节转换为MIMEtypes的blob非常简单。

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

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

我喜欢@ Breedly的想法是预定一个固定长度的字节数组来表示ArrayBuffer的mimetypes,所以我创build了这个npm包 ,当我使用websockets的时候,也许别人会觉得它有用。

用法示例

 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