1

Express.js を使用して webapp を作成しています。

私のwebappは以下を達成します

  1. ユーザーが 100 個の json オブジェクトを投稿
  2. 各 json オブジェクトはサービス呼び出しを介して処理されます
  3. サービス呼び出しが完了すると、セッション変数がインクリメントされます
  4. セッション変数の増加時に、進行状況バーを更新するためにサーバー側イベントをクライアントに送信する必要があります

サーバー送信イベントをトリガーするためにセッション変数の変更をリッスンするにはどうすればよいですか?

変数の変更を聞くことが、私が求める唯一の解決策ではありませんか?

JSON オブジェクトが処理されたら、サーバー送信イベントを送信する必要があります。

適切な提案は大歓迎です

編集 (Alberto 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. 最初のレコードが更新され、responseObject (高速応答オブジェクト) を使用してサーバー側イベントがトリガーされたとき

  2. 2 番目のレコードが更新されたときに、同じ responseObject を使用してサーバー側のイベントをトリガーしようとしました。既に送信された応答にヘッダーを設定できないというエラーが表示されます

4

2 に答える 2

0

メインアプリケーションにあるルート/アクションを見ずに、状況を正確に知ることは困難です...

しかし、あなたが直面している問題は、許可されていない 2 つのヘッダー セットをクライアント (ブラウザー) に送信しようとしていることにあると思います。これが許可されていない理由は、最初の応答を送信した後に応答のコンテンツ タイプを変更することがブラウザで許可されていないためです。これらのヘッダー (またはその他のヘッダー) は、クライアントに一度送信した後は変更できません (1 つの要求 -> 1 つの応答 -> 1 つのヘッダー セットをクライアントに送り返す)。これにより、サーバーが統合失調症のように見えるのを防ぎます (たとえば、"200 Ok" 応答から "400 Bad Request" に切り替えることによって)。

この場合、最初のリクエストで、クライアントに「ねえ、これは有効なリクエストでした。これが私の応答です (他の場所に設定されているか、ExpressJS によって想定されている 200 のステータスを介して)。コミュニケーションを維持してください」と伝えます。チャンネルを開いているので、更新情報を送信できます (コンテンツ タイプを に設定してくださいtext/event-stream)".

これを「修正」する方法に関しては、多くのオプションがあります。これが完了したら、redis の pub/sub 機能を使用して、すべてを接続する「パイプ」として機能させました。というわけで、以下の流れになりました。

  1. 一部のクライアントがリクエストを送信します/your-event-stream-url

    このリクエストでは、Redis サブスクライバーを設定します。このサブスクリプションに含まれるものはすべて、必要に応じて処理できます。あなたの場合、「少なくともdata属性を持つJSONオブジェクトでパイプを介してクライアントにデータを送信する」必要があります。このクライアントを設定したら、「200 Ok」という応答を返し、コンテンツ タイプを「text/event-stream」に設定するだけです。残りは Redis が処理します。

  2. 次に、別の URL エンドポイントに対して別のリクエストが行われ、「JSON オブジェクトを投稿する」というタスクを実行します/your-endpoint-that-processes-json.(注: 明らかに、このリクエストは同じユーザー/ブラウザによって行われる可能性があります...しかし、アプリケーションは知りません/気にしません)。そのことについて)

    このアクションでは、JSON データの処理を行ったり、カウンターをインクリメントしたり、何でもします...そして 200 応答を返します。ただし、このアクションで行うことの 1 つは、ステップ 1 のサブスクライバーがリッスンしている Redis チャネルでメッセージを「公開」して、クライアントが更新を取得することです。技術的には、このアクションはクライアントに何も返す必要はありません。ユーザーが 200 ステータス コードまたはパイプを介して送信されたサーバー送信イベントに基づいて何らかのフィードバックを受け取ると仮定して...

私があなたに与えることができる具体的な例は、この記事の一部であるこの要点です。この記事はこの時点で数年前のものであるため、コードの一部を少し調整する必要がある場合があることに注意してください。また、これは例以上のものであることが保証されていないことに注意してください (つまり、「負荷テスト」などは行われていません)。ただし、開始するのに役立つ場合があります。

于 2013-07-26T16:30:40.963 に答える
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);
于 2013-07-27T00:32:21.943 に答える