服务器发送事件如何向特定客户端发送响应

17
在服务器发送事件中,它总是向所有客户端发送相同的响应。但我想知道的是,如何使用Java只向一个客户端发送响应。
这是我在sw.js(SSE)内定义的事件。
var eventSource = new EventSource("HelloServlet");
eventSource.addEventListener('up_vote',function(event){
    console.log("data from s" , event.data);
    var title = event.data;
    self.registration.showNotification(title, {
          'body': event.data,
          'icon': 'images/icon.png'
        })
});

我希望只向特定用户显示此通知,而不是所有人。HelloServlet是我的servlet,并包含以下内容:

response.setContentType("text/event-stream");   
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        String upVote = "u";
        String downVote = "d";
        for(int i=0; i<10; i++) {
            writer.write("event:up_vote\n");
            writer.write("data: "+ upVote +"\n\n");
            writer.write("event:down_vote\n");
            writer.write("data: "+ downVote +"\n\n");
            writer.flush();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        writer.close();

发送作为流的JSON编码字符串。例如,"{userId:4, eventType:like}"。在客户端上,解析JSON并获取对象。 - Saqlain
3个回答

21

你之所以只向所有客户端发送相同的消息,是因为你只有一个频道,他们都连接到这个频道。 EventSource 只是一个保持打开状态的 GET 请求。与任何 get 请求一样,您可以通过几种方式将其专门定制给特定用户。

var eventSource = new EventSource("HelloServlet?username=their-user-name");
在这个例子中,您正在使用查询字符串为每个人创建唯一的通道。然后您需要在服务器端编写逻辑根据 username 变量发送不同的内容。
您还可以使用会话。因此,您可以在客户端保留当前代码。
var eventSource = new EventSource("HelloServlet");
但在服务器端,您需要检查会话,然后根据会话信息发送不同的内容。
这有帮助吗?

1-这是否意味着服务器将为每个连接的用户提供一个通道? 2-如果您使用会话,如何在发送事件时针对特定用户? - ramazan polat
2
@RamazanPolat - 当用户连接时,他们会创建一个保持打开状态的到您的服务器的连接。当他们连接时,您正在决定他们连接到哪个频道。执行的代码是标准的服务器端代码。因此,在呈现HTML页面或响应REST调用时可用的所有相同内容都可用。所以回答你的问题:(1)是的。(2)当创建EventSource时,您需要创建一个包括该会话的ID的命名通道。在发布时,您需要知道该ID并发布到该通道。 - baynezy
我已经实现了使用查询字符串作为“键”的功能。您可以在此处查看一个最小的示例(https://gist.github.com/mirusky-enube/78fc9ca68af913e2f122fc94c6c78a2f)。 - Mirusky

4

我知道这篇帖子很旧了,但它仍然值得提及一个解决此问题的方法。我有一个或多个相同的用例,需要向用户发布通知,并且每个用户都将拥有自己的通知。

我使用了一个简单的技巧,EventSource监听事件,我将userId附加为事件类型的一部分,以区分各个用户。

因此,我没有使用on up_vote,而是使用up_vote_userId1。我们的后端基于哪个用户有更新来发布这些事件类型的事件。我们的问题得到了解决。


2
采用这种方法,您需要确保恶意客户端不会订阅其他用户的事件(当其他用户可能无法访问事件数据时)。 - cnmuc

1
我推荐您使用JEaSSE库(Java Easy Server-Sent Events):http://mvnrepository.com/artifact/info.macias/jeasse 您可以在这里找到一些使用示例:https://github.com/mariomac/jeasse 特别地,针对您的用例:
@WebServlet(asyncSupported = true)
public class ExampleServlet1 extends HttpServlet {

    SseDispatcher dispatcher;;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                                      throws ServletException, IOException {
       dispatcher = new SseDispatcher(req).ok().open();
    }

    public void onGivenEvent(String info) {
       dispatcher.send("givenEvent",info);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接