我在使用 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 并使用 servlet 添加 WebAppContext 的摘录(包含在一个大的 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()
curl
的输出:
> 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>
最佳答案
我怀疑问题出在 jetty 上.我注意到,当尝试使用 jersey2 消耗 Marathon
事件(通过 /v2/events
)时客户端,它用 \r\n
而不是 \n\n
分隔事件,所以它只是坐在那里填充缓冲区,从不返回控制。
关于java - 使用 Jetty(编程设置)的服务器发送事件 (SSE),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31696757/