2013-07-26 75 views
1

我正在使用express.js編寫web應用程序。一旦服務呼叫完成Node.js偵聽會話變量更改並觸發服務器發送的事件

我的web應用程序實現以下

  1. 用戶訊息100 JSON對象
  2. 每個JSON目的通過一種服務呼叫
  3. 處理,會話變量被遞增
  4. 在增加會話變量時,必須向客戶端發送服務器端事件以更新進度條

如何實現監聽會話變量更改以觸發服務器發送的事件?

傾聽變量變化不是我尋求的唯一解決方案嗎?

我需要在處理JSON對象後實現發送服務器發送的事件。

任何適當的建議是歡迎

編輯(基於阿爾貝託Zaccagni的評論)

我的代碼如下所示:

function processRecords(cmRecords,requestObject,responseObject) 
{ 
    for (var index = 0; index < cmRecords.length; index++) 
    { 
     post_options.body = cmRecords[index]; 
     request.post(post_options,function(err,res,body) 
     { 
      if(requestObject.session.processedcount) 
       requestObject.session.processedcount = requestObject.session.processedcount + 1; 
      else 
       requestObject.session.processedcount = 1; 

      if(err) 
      { 
       appLog.error('Error Occured %j',err); 
      } 
      else 
      { 
       appLog.debug('CMResponse: %j',body); 
      } 

      var percentage = (requestObject.session.processedcount/requestObject.session.totalCount) * 100; 

      responseObject.set('Content-Type','text/event-stream'); 
      responseObject.json({'event':'progress','data':percentage}); 
     }); 
    }; 


} 
  1. 當第一個記錄被更新和服務器使用響應對象(快速響應對象)觸發旁邊事件

  2. 當第二條記錄更新時,我嘗試使用相同的responseObject觸發服務器端事件。我得到一個錯誤說不能設置標頭已經被髮送的響應

+0

爲什麼你要聽的變量?爲什麼不在更新它時發送正確的事件? –

回答

0

這是很難知道的情況是什麼,沒有看到你在你的主應用程序具有路由/動作......

不過,我相信你遇到的問題是你正試圖發送兩套頭到客戶端(瀏覽器),這是不允許的。這是不允許的原因是因爲瀏覽器不允許您在發送初始響應之後更改響應的內容類型......因爲它使用該響應作爲如何處理您發送響應的指示符。發送給客戶端一次(一個請求 - >一個響應 - >一個標頭返回給客戶端)之後,您不能更改這些(或任何其他標頭)。這可以防止服務器顯示精神分裂症(例如,通過從「200 Ok」響應切換到「400 Bad Request」)。

在這種情況下,在最初的請求中,您告訴客戶端「嘿,這是一個有效的請求,這是我的迴應(通過200的狀態,可能是其他地方設置的或由ExpressJS承擔的)請保持溝通渠道暢通,以便我可以向您發送更新(通過將您的內容類型設置爲text/event-stream)「。

至於如何「修復」這個,有很多選擇。當我完成這些時,我已經使用redis的pub/sub功能來充當連接所有東西的「管道」。因此,流程一直是這樣:

  1. 某些客戶端發送到/your-event-stream-url

    的請求在該請求中,您設置Redis的用戶。無論您想要如何處理此訂閱中的任何內容,都可以進行處理。在你的情況下,你想「通過一個至少具有data屬性的JSON對象將管道中的一些數據發送到客戶端。」設置此客戶端後,您只需返回「200 Ok」的響應,並將內容類型設置爲「文本/事件流」。 Redis將負責其餘的事情。

  2. 然後,另一個請求到擊中/your-endpoint-that-processes-json.(注完成的「張貼JSON對象」任務的另一個URL端點做:顯然這個要求由同一個用戶/瀏覽器進行......但是應用程序不知道/關心)

    在此操作中,您將處理其JSON數據,增加計數器或執行任何操作...並返回200響應。但是,您在此操作中執行的其中一項操作是在#1用戶正在監聽的Redis頻道上「發佈」一條消息,以便客戶端獲得更新。從技術上講,這個動作不需要返回任何東西給客戶端,假設用戶會根據200-狀態代碼或發送服務器發送的事件發送某種類型的反饋...

我可以給你的一個實例是this gist,它是this article的一部分。請注意,這篇文章已經有幾年了,所以有些代碼可能需要稍微調整一下。另外請注意,這不能保證只是一個例子(即:它沒有被「加載測試」或類似的東西)。但是,它可以幫助您開始。

0

我想出了一個解決方案,請讓我知道如果這是正確的方式做東西?

此解決方案是否可以跨會話使用?

服務器端代碼

var events = require('events'); 
var progressEmitter = new events.EventEmitter(); 

exports.cleanseMatch = function(req, res) 
{ 
    console.log('cleanseMatch Inovked'); 
    var progressTrigger = new events.EventEmitter; 
    var id = ''; 
    var i = 1; 

    id = setInterval(function(){ 
     req.session.percentage = (i/10)*100; 
     i++; 
     console.log('PCT is: ' + req.session.percentage); 
     progressEmitter.emit('progress',req.session.percentage) 

     if(i == 11) { 
     req.session.percentage = 100; 
     clearInterval(id);    
     res.json({'data':'test'}); 
     } 
    },1000); 
} 

exports.progress = function(req,res) 
{ 
    console.log('progress Inovked'); 
    // console.log('PCT is: ' + req.session.percentage); 

    res.writeHead(200, {'Content-Type': 'text/event-stream'}); 
    progressEmitter.on('progress',function(percentage){ 
     console.log('progress event fired for : ' + percentage); 
     res.write("event: progress\n"); 
     res.write("data: "+percentage+"\n\n"); 
    }); 
} 

客戶端代碼

var source = new EventSource('progress'); 
source.addEventListener('progress', function(e) { 
    var percentage = JSON.parse(e.data); 
    //update progress bar in client 
    App.updateProgressBar(percentage); 
}, false); 
相關問題