Java Servlet和服务器发送事件

13

是否可以使用Java Servlet创建服务器推送事件,以便客户端可以使用以下方式接收更新:

 <script>
   var source = new EventSource('/events');
   source.onmessage = function(e) {
     document.body.innerHTML += e.data + '<br>';
   };
 </script>

我在网上找到的所有示例都使用PHP编写,但我认为可以使用Java的HTTP Servlet实现同样的功能。


你正在寻找HTML5的 "Server-Sent Events" 特性,对吗?http://today.java.net/article/2010/03/31/html5-server-push-technologies-part-1 - Robert
是的,事件应该使用Java Servlet创建。 - Chris
Servlets 只能响应传入的 HTTP 请求。它们并不是设计用于保持连接的。虽然你可以这样做,但我认为如果你这样做,你的服务器将非常快地用尽工作线程。 - Robert
1
Servlet可以保持连接处于打开状态--只需不从doGet/doPost方法返回(并且显然不要手动关闭任何流)。但正如Robert所说,您通常只有一个由Web服务器允许的有限连接池。一旦用完了这些连接,您就无法处理任何新连接,直到开始关闭旧连接为止。 - Jack Edmonds
1
这可能会有所帮助。http://blog.maxant.co.uk/pebble/2011/06/21/1308690720000.html - Varun
这个问题的答案(链接)比这里的任何答案都更有用,它提供了一个你可能真正想要做的示例:异步响应。 - lpd
3个回答

7
这个能起到作用。
HTML
<!DOCTYPE html>


<html>
<body onload ="registerSSE()" >
    <script>

        function registerSSE()
        {
            alert('test 1');
            var source = new EventSource('http://frewper:8080/hello/sse');  
            alert('Test2');
            source.onmessage=function(event)
            {
                document.getElementById("result").innerHTML+=event.data + "<br />";
            };

            /*source.addEventListener('server-time',function (e){
                alert('ea');
            },true);*/
        }
    </script>
    <output id ="result"></output>

</body>
</html>

Servlet :

import java.io.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;




public class sse extends HttpServlet
{
public void doPost(HttpServletRequest request, HttpServletResponse response)
{
    try
    {
        System.out.println("SSE Demo");
        response.setContentType("text/event-stream");

        PrintWriter pw = response.getWriter();
        int i=0;
        while(true)
        {

            i++;
            pw.write("event: server-time\n\n");  //take note of the 2 \n 's, also on the next line.
            pw.write("data: "+ i + "\n\n");
            System.out.println("Data Sent!!!"+i);
            if(i>10)
            break;
        }
        pw.close();

    }catch(Exception e){
        e.printStackTrace();
    }
}

public void doGet(HttpServletRequest request,HttpServletResponse response)  
{
    doPost(request,response);
}

}

1
我在JDK 1.6.0_25和使用Jetty的Chrome浏览器上尝试过,但似乎无效。servlet接收了请求并将“数据已发送”消息打印到控制台,但网页没有响应。您使用的JDK版本和浏览器是什么?我对这整个领域都很新。 - DPD
使用了JDK 1.6.0_24版本,我使用Tomcat进行开发,一切都运行得非常完美。同时请检查您的浏览器是否支持"SSE"。最好使用Chrome或最新版本的Firefox。 - frewper
我遇到了一个错误:“EventSource的响应具有不是UTF-8的字符集(“iso-8859-1”)。中止连接。” 我认为这是默认编码。请添加 response.setCharacterEncoding("UTF-8"); - Bakudan
请注意,@frewper提供的代码在我的电脑上无法运行。我已经创建了两个文件,但是我想知道是否需要包含一些库?请回答。 - Souad
1
我不得不在写入 PrintWriter 后添加 response.flushBuffer()。否则,消息可能不会立即发送,而是在 doPost 方法完成时一次性发送。 - mihca

4

服务器发送事件是HTML5的一个功能。我们说“HTML5”,因此它只是客户端的功能。 只要服务器可以设置https响应头"text/event-stream;charset=UTF-8","Connection","keep-alive",那么它就受到服务器的支持。您可以使用Java Servlet设置此类标头。 在这里,您可以找到有关使用Servlet进行SSE的逐步指南


1
我创建了一个非常简单的库,可以在异步模式下集成到纯Java Servlets中,因此不需要为每个客户端额外的服务器线程:https://github.com/mariomac/jeasse 它集成了SseDispatcher(用于点对点SSE)和SseBroadcaster(用于事件广播)。以下是使用示例:
public class TestServlet extends HttpServlet {

SseBroadcaster broadcaster = new SseBroadcaster();

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    Scanner scanner = new Scanner(req.getInputStream());
    StringBuilder sb = new StringBuilder();
    while(scanner.hasNextLine()) {
        sb.append(scanner.nextLine());
    }
    System.out.println("sb = " + sb);
    broadcaster.broadcast("message",sb.toString());
}

//http://cjihrig.com/blog/the-server-side-of-server-sent-events/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    broadcaster.addListener(req);
}
}

看起来很有趣。但是为什么你要使用LGPL许可证(而不是例如Apache 2)? - Tom Fennelly
@TomFennelly 我基本上随意选择了一种可以在派生代码中自由使用而没有限制的许可证。您建议我使用另一个吗?LGPL 有什么缺点吗? - Mario
就商业友好性而言,Apache 2 在对使用它的人在产品中的限制方面较少具有传染性。 - Tom Fennelly

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