使用Jetty进行服务器推送事件(SSE)的编程设置

3
我在使用Jetty设置SSE环境时遇到了问题。我使用Chrome(44.0.2403.107 m)和FF(39.0)作为客户端浏览器。
我在Jetty中创建了一个servlet(如下所示),并使用WebAppContext使其可编程使用。我还尝试使用Jetty提供的“EventSourceServlet”,但这也不起作用。
在客户端方面,我创建了一个简单的“EventSource”,并尝试获取消息。虽然“curl”提供了正确的输出(见下文输出),但FF和Chrome没有按预期触发事件。在关闭服务器后,事件似乎会在浏览器中弹出(超时请求后)。
有人可以指出我在使用Jetty实现SSE时的错误吗?
我还注意到Jetty使用特殊的“write”方法来进行异步写操作。但是,在“EventSourceServlet”中未使用这些方法。我必须使用它们才能使SSE正常工作吗?此外,在我的servlet中,哪些部分可以省略“flush”操作?
我创建的servlet:
package de.rub.lps.sophie.agenten.sample.webui.servlet;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.AsyncContextState;

public class TestServlet extends HttpServlet {

    private static final long serialVersionUID = -8049945594360149181L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println(req.getSession(true).getId());

        resp.setStatus(HttpServletResponse.SC_OK);
        resp.setContentType("text/event-stream");
        resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
        resp.flushBuffer();
        AsyncContextState async = (AsyncContextState) req.startAsync();

        System.out.println(async);

        new Thread() {
            public void run() {
                try {
                    for (int i = 0; i < 3; i++) {
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        ServletOutputStream outputStream = async.getResponse().getOutputStream();
                        if (outputStream.isReady()) {
                            String message = "data: refresh\n\n";
                            outputStream.write(message.getBytes(StandardCharsets.UTF_8), 0, message.length());
                            outputStream.flush();
                            async.getResponse().flushBuffer();
                        } else {
                            System.out.println("not ready!");
                        }
                        System.out.println("wrote!");
                    }
                } catch (IOException e) {
                    async.complete();
                    e.printStackTrace();
                }
            };
        }.start();
    }

}

以下是我如何启动Jetty并添加WebAppContext与servlet的摘录(包含在一个大的try/catch中...):

HandlerCollection handlerCollection = new HandlerCollection(true);
server = new Server(8888);
server.setHandler(handlerCollection);
server.start();

WebAppContext context = new WebAppContext();
handlerCollection.addHandler(context);
context.setContextPath("/test");
context.setResourceBase("/myPath");
ServletHolder servletHolder = new ServletHolder(new TestServlet());
servletHolder.setAsyncSupported(true);
context.addServlet(servletHolder, "/test");
context.start()
< p > curl 的输出结果:< /p>
> GET /Agentname@134.147.100.87:1099/JADE/test HTTP/1.1
> Host: 127.0.0.1:8888
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Jul 2015 09:08:05 GMT
< Set-Cookie: JSESSIONID=aw6ro34htalm1uf5huix9bxo6;Path=/test/test
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Content-Type: text/event-stream;charset=utf-8
< Transfer-Encoding: chunked
< Server: Jetty(9.3.1.v20150714)
<

data: refresh

data: refresh

data: refresh

[... and so on...]

我在浏览器中使用的test.html文件:

<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<script>
 var eventSource = new EventSource('test');
 eventSource.onmessage = function(event) {
     console.log(event);
     window.alert(event.data);
 };
</script>

</body>
</html>
1个回答

1
我怀疑问题出在 上。我注意到,当尝试使用 客户端消费 Marathon 事件(通过 /v2/events)时,它会使用 \r\n 分隔事件而不是 \n\n,因此它只是坐在那里填充缓冲区并永远不会返回控制。

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