2014-03-03 32 views
3

現在,我有一個node.js服務器能夠使用流API在GET請求上傳輸數據。 GET請求是傳輸編碼設置爲「分塊」。數據可以在10到30 MB的數量級上。 (他們有時候是3D模型)如何處理流式傳輸HTTP GET數據?

在瀏覽器端,我希望能夠處理數據,因爲我正在下載它 - 我希望能夠在畫布上顯示數據,因爲我正在下載它。所以當數據進入時,您可以看到3D模型正面顯示。我不需要雙工通信,也不需要持續連接。但我確實需要在下載數據後立即處理數據,而不是等待整個文件完成下載。然後在瀏覽器下載數據後,我可以關閉連接。

我該怎麼做?

JQuery ajax只有在接收到所有數據時纔會回撥。

我也看了portal.js(這是jquery流)和socket.io,但他們似乎假設持久重新連接。

到目前爲止,我能夠使用原始XMLHttpRequest破解解決方案,並在readyStead> = 2 & & status == 200時進行回調,並跟蹤上次讀取的位置。但是,這將保留原始XMLHttpRequest中下載的所有數據,這是我不想要的。

似乎有更好的方法來做到這一點,但我不知道它是什麼。任何人都有建議?

回答

1

所以我找到了答案,它是服務器發送的事件。它基本上支持瀏覽器一次處理塊的單向HTTP流。這可能有點棘手,因爲一些現有的流庫已經損壞(他們不認爲你在流中有\ n,因此你會得到部分數據),或者幾乎沒有文檔。但是推出自己的產品並不難(一旦你明白了)。在服務器端然後

// file sse_stream.coffee 
var Transform = require('stream').Transform; 
var util = require('util'); 
util.inherits(SSEStream, Transform); 

function SSEStream(option) { 
    Transform.call(this, option); 
    this.id = 0; 
    this.retry = (option && option.retry) || 0; 
} 

SSEStream.prototype._transform = function(chunk, encoding, cb) { 
    var data = chunk.toString(); 
    if (data) { 
    this.push("id:" + this.id + "\n" + 
     data.split("\n").map(function (e) { 
     return "data:" + e 
     }).join("\n") + "\n\n"); 
    //"retry: " + this.retry); 
    } 
    this.id++; 
    cb(); 
}; 

SSEStream.prototype._flush = function(next) { 
    this.push("event: end\n" + "data: end" + "\n\n"); 
    next(); 
} 

module.exports = SSEStream; 

(我用的是快遞),你可以做這樣的事情:

您可以定義sse_transform這樣

sse_stream = require('sse_stream') 
app.get '/blob', (req, res, next) -> 
    sse = new sse_stream() 

    # It may differ here for you, but this is just a stream source. 
    blobStream = repo.git.streamcmd("cat-file", { p: true }, [blob.id]) 

    if (req.headers["accept"] is "text/event-stream") 
    res.type('text/event-stream') 
    blobStream.on("end",() -> res.removeAllListeners()).stdout 
     .pipe(
     sse.on("end",() -> res.end()) 
    ).pipe(res) 
    else 
    blobStream.stdout.pipe(res) 

然後在瀏覽器端,你可以這樣做:

source = new EventSource("/blob") 
    source.addEventListener('open', (event) -> 
     console.log "On open..." 
    , false) 
    source.addEventListener('message', (event) -> 
     processData(event.data) 
    , false) 
    source.addEventListener('end', (event) -> 
     console.log "On end" 
     source.close() 
    , false) 
    source.addEventListener('error', (event) -> 
     console.log "On Error" 
     if event.currentTarget.readyState == EventSource.CLOSED 
     console.log "Connection was closed" 
     source.close() 
    , false) 

請注意,您需要監聽事件'結束',這是從se rver在變換流的_flush()方法中。否則,瀏覽器中的EventSource會一遍又一遍地請求同一個文件。

請注意,您可以使用服務器端的庫來生成SSE。在瀏覽器端,您可以使用門戶。js處理SSE。我只是拼寫出來,所以你可以看到事情會如何運作。

1

oboe.js是一個用於在瀏覽器中傳輸響應的庫。

但是,這保留了原始XMLHttpRequest下載的所有數據,這是我不想要的。

我懷疑這可能是oboe.js的情況,也可能是XMLHttpRequest本身的限制。不確定,因爲我沒有直接處理這類用例。很想看看你的努力和對這個問題的其他答案。

+0

謝謝你的擡頭。我對oboe.js進行了粗略瀏覽,並查看了他們的流式課程,發現它確實使用了xhr。我試圖通過將xhr的responseText字段設置爲null或「」來清除它的responseText字段,但那不起作用。我不懷疑它會在oboe.js中起作用。它似乎是我描述的黑客的正式版本,在轉移完成之前您開始回調。 – Wilhelm