2015-04-02 120 views
4

我不是100%確定,但從我讀取當我通過websocket發送blob(二進制數據)時,blob不包含任何文件信息。我使用https://github.com/websockets/wsnodejs二進制websocket mimetype處理

(也正式規範規定wesockets只發送原始二進制)

  1. 文件大小
  2. 的MIME類型
  3. 用戶信息(在後面解釋)

測試:

直接從輸入文件發送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和文件大小等重要信息的二進制文件,然後在需要的時候分開4kb?

{ 「MIME」: 「TXT /純」, 「大小」:345} ____________ 4KB_REST_OF_THE_BINARY

OR

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

即使第一個是最差解決方案有史以來它可以讓我一次發送一切。

第二個有一個很大的問題:

這是一個聊天,允許也發送文件,如文檔,圖片,音樂視頻。

在發送二進制數據之前,我可以在發送文件/用戶信息時寫一些握手系統。

如果另一個人也發送一個文件,因爲它是異步,握手系統沒有機會來確定至極文件是正確的用戶和MIME類型是正確的。

那麼如何在多用戶異步環境中正確發送二進制文件?

我知道我可以轉換爲base64,但是這大了30%。

btw。共與蘋果失望... ... - 雖然chrome可以正確顯示每個二進制數據,但我的ios設備無法處理blob,只有圖像以blob或base64格式顯示,甚至不是簡單的txt文件。基本上只有一個<img>標籤可以讀取動態文件。

一切是如何工作的(現在):

  1. 用戶發送一個文件
  2. 得到的NodeJS二進制數據,還用戶信息...但不是MIME類型,文件名,大小。
  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

aaaaaand的MIME類型不見了...

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我需要的MIME類型,自然我也需要有關用戶的信息,可以至極從客戶端1服務器(不是一個好的選擇)檢索...

+0

你有沒有想過使用BinaryPack? https://github.com/binaryjs/node-binarypack https:// github。com/binaryjs/js-binarypack – Ben 2015-04-08 17:24:10

+0

對不起,我試圖用ws(websockets)來實現它 – cocco 2015-04-08 17:52:06

+0

Right,BinaryJack是BinaryJS用於通過websocket傳輸文件等的東西http://binaryjs.com/ – Ben 2015-04-08 18:33:09

回答

4

因爲Node不支持Blob接口,所以你在Binary with Node中發送或接收的任何數據都是二進制的。你將不得不有一些知道如何解釋Blob對象的東西。

這是一個想法,讓我知道這是否工作。閱讀websockets\ws的文檔說它支持發送和接收ArrayBuffers。這意味着你可以使用TypedArrays

這是它變得討厭的地方。你設置了一個固定的n在每個TypedArray開頭的字節數來表示用utf8編碼的MIME類型或你有什麼,其餘的TypedArray包含你文件的字節。

我會推薦使用UInt8Array,因爲utf8字符長度爲8位,並且在編碼時可能會讀取文本。至於文件位,您可能最終只會將這些文件寫入某處並在其後添加一個結尾。

另請注意,無論是來自Node還是瀏覽器,這種解釋方法都可以使用。

此解決方案實際上只是一種類型轉換的形式,您可能會得到一些意外的結果。您的mime類型字段的固定長度至關重要。

這裏說明。複製,粘貼,設置圖像文件到任何你想要的,然後運行。你會看到我彈出的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:獲得一個PACKAGE

獲取buffer,節點的緩存API的瀏覽器的實現。連接字節緩衝區的解決方案將與以前完全一樣。你可以附加To:等字段,還有什麼不好。爲了更好地爲您的客戶提供服務,您設置標題的方式將是一個不斷演變的過程,我相信。

解決方案B:OLD SCHOOL

STEP 1:將您斑點一個ArrayBuffer

注:How to convert a String to an 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); 

STEP 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步:接收和Reblob

我不會重複如何轉換,因爲我已經在服務器實例做了它的連接字符串字節回字符串,但打開文件字節到你的MIME類型的blob是相當簡單的。

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

This Gist通過robnyman進入你將如何使用通過XHR發送的圖像,把它放到本地存儲,並在您的網頁上的圖像標籤使用的詳細信息。

+0

是的,這正是我想解釋這個問題。 「第一個解決方案」將使用UInt8Array存儲該信息....但是如何?請記住,客戶端上的JavaScript需要對二進制數據進行內插和解碼...... nodejs只需傳遞消息....這樣我就可以用二進制發送所有東西。 – cocco 2015-04-08 21:25:31

+0

它會更好,如果我的二進制信息的大小可變。像thew id3或exif ... – cocco 2015-04-08 21:27:27

+0

btw我可以將arraybuffer轉換爲blob ... – cocco 2015-04-08 21:28:21

0

我喜歡@ Breedly的想法是預定一個固定長度的字節數組來表示ArrayBuffer的MIME類型,所以我創建了這個npm package,我在處理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