【问题标题】:how to differentiate between different server sent event listeners?如何区分不同服务器发送的事件监听器?
【发布时间】:2016-01-01 11:45:59
【问题描述】:

我有一个应用程序,在该应用程序中,不同的用户监听服务器发送的事件源以获取定期响应。我打算从服务器发送具有相应 ID 和 json 格式数据的响应。在客户端,每个客户端在数据到达时检查匹配如果发现它处理数据,则忽略它。但是这种方法的缺陷是每个用户都从定期更新中获取数据,即使它不是为他们准备的。我读了几篇关于 sse 的文章,但找不到任何关于这个

我的问题是使用服务器端事件是否有任何方法可以向特定的侦听器发送响应,如果可以,如何.?

【问题讨论】:

  • 是的,实际上您必须将其发送给特定的;广播功能只是循环所有用户并向每个用户发送相同的消息...在发送之前在服务器上运行您的 IF,而不是在客户端到达后...
  • @dandavis 如何使用自定义事件名称将其发送给特定的人?
  • 我刚刚注意到标签。您是在问如何在客户端处理消息? (不管怎样,我认为不需要jquery标签?)
  • 如何做到这一点对于您的服务器端实现非常特殊。那么你能详细说明一下你的工作原理吗?
  • @baynezy 我可以用代码提供完整的骨架结构,但它会很长

标签: javascript jquery server-sent-events


【解决方案1】:

更新基于问题澄清:如何阻止客户端接收不适合它的 SSE 消息。

最好的方法是不发送。在服务器端过滤消息。 (正如我回答的前面部分所解释的,这很容易,因为每个 SSE 连接已经有一个专用服务器进程来决定向它发送哪些数据。)这种方法在所有方面都优越(CPU/内存、网络带宽、安全性、隐私、程序员工作量)。

另一种方法是在客户端过滤它,有两种方法可以做到这一点。一种是向客户端发送 json 数据。在您的 onMessage() 处理程序中,使用这些字段之一来确定此消息是否针对此客户端。

另一种是使用 SSE 的 event: 字段,然后监听该消息:

es = new EventSource(...);
es.addEventListener("forUser123", function(e) {
  //Process their data here
  }, false);

event:forUser123 标头将在您发送 data: 字段之前在服务器上设置。 (但是,如果您不得不麻烦添加一个额外的标头,最好在此时过滤您发送的消息。)


原答案

您想做的事情(特定于客户端)很容易,而您认为 Server-Sent-Events 的工作方式(广播)更难。

到您的服务器的每个EventSource 连接都是一个专用套接字。所以它就像任何其他与 Web 服务器的连接一样,唯一的区别是套接字没有关闭,而是保持打开状态,以便服务器可以继续发送数据。这也意味着服务器上有一个专用进程或线程来处理要发送到该客户端的消息。

因此,服务器知道每个用户是谁(假设他们通过会话 cookie 来标识自己),并且可以选择向该客户端发送哪些数据。

旁白:为什么广播更难?假设您有 100 个连接的 SSE 客户端 - 您实际上有 100 个独立的服务器进程在运行。要将单个消息广播给所有 100 个,您首先必须告诉这 100 个服务器端进程该消息是什么,以便它们可以传递它。您可以使用上游套接字执行此操作,或者他们可能会定期轮询“messagesToSendToEveryone”数据库表以查看是否添加了任何新内容。

【讨论】:

  • 它的实际查询聊天应用程序用户无需登录即可向服务器发送聊天。服务器会定期检查数据库中的传入聊天,然后制定回复并插入表以获取聊天日志表,并且 sse 提要生成页面检查未查看的消息并广播消息每个客户端源分析消息,如果 Id 匹配附加到聊天作为回复。我问你如何将数据发送到特定的客户端监听器,为你的努力而投票
  • @SachinDivakar 这一切听起来都是我的做法,所以我不确定你剩下的问题是什么?一旦你为你的用户轮询了数据库,你只需将输出写入标准输出。
  • 是的,客户端是服务器监听器监听事件源的地方,当接收到数据时,它会检查其用户是否正确。所以我的问题是如何防止数据在客户端暴露给用户跨度>
  • @SachinDivakar 我用更多解释更新了我的答案。希望对您有所帮助。
  • 我再次按照同样的思路思考实际上完全相同的方式。我已经实现了自定义事件。首先,当用户注册聊天时,它返回自定义标识 ID 作为来自服务器的响应。所以服务器广播结果将转到相应的事件侦听器,但这种方法让我遇到了一个新问题,所以我问了这个问题,以确定是否有任何其他透视
【解决方案2】:

我所做的是注册用户/询问用户登录并返回一个唯一的标识密钥。使用此密钥作为事件名称事件侦听器在注册/登录 $post(); 的回发成功函数中初始化。

所以基本上每个事件侦听器都会监听一个唯一的事件。在服务器端,每个事件名称都会被广播,然后是数据,因此唯一的事件侦听器会收到只为他们准备的消息。

客户端

$.post( "chatReg.php", { xxx: xxxx, time: xxx}).done(function( data ) {

     if((typeof(EventSource) !== "undefined")&&((localStorage.getItem("uname") !== null))) {
    var source = new EventSource("XXXXXXXX.php");   

    source.addEventListener(localStorage.getItem("uname"), function(e) {
     var data = JSON.parse(e.data);

     $('div.chat-box-content').append('<div class="msgWrapper"><div class="msgwrapperleft"><div class="iconright"><img src="http://placehold.it/40X40"></img></div><div class="MessageRight">'+data.Message+ '</div> </div><p class="ArrivedTimeRight"><span ><span class="timeago" >'+CreateTimestamp()+'</span></span></p></div>');

    }, false);


    } 

}

服务器

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header("refresh: 5;");

    echo  'event: '.$row['SpecialId'];
            echo PHP_EOL;

            echo  'data: {"Message":"'.$row['Message'].'","xxxId":"'.$row['xxxId'].'"}';
            echo PHP_EOL;
            echo PHP_EOL;

【讨论】:

猜你喜欢
  • 2018-09-24
  • 2011-09-28
  • 2015-05-23
  • 2018-06-28
  • 2022-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
相关资源
最近更新 更多