SSE 的原理以及java下的简单实现
前段时间看到gpt返回时的部分输出的效果,觉得很有意思,所以研究了下是怎么实现的。
主要是通过sse(Server-Sent Events)技术实现的这种效果
简介
SSE(Server-Sent Events)和WebSocket都是用于实现服务器和客户端之间的实时通信的技术,但它们有一些区别。
SSE是一种单向通信协议,它允许服务器向客户端发送事件流。客户端通过一个持久化的HTTP连接接收事件流,这个连接可以保持打开状态,直到客户端关闭连接或服务器关闭连接。
WebSocket是一种双向通信协议,它允许服务器和客户端之间进行实时双向通信。WebSocket通过一个持久化的TCP连接实现双向通信,客户端和服务器可以随时发送消息。
sse
1.如何保持长连接
在http 1.1下Keep-Alive模式默认开启,服务端会通过tcp协议发送一个不带数据的ack请求,确保客户端的在线。
2.如何判断数据完整性
当客户端接收到数据后会通过判断Content-Length
或者Transfer-Encoding
响应头判断哪一部分是完整数据。
3.客户端如何判断是sse
通过客户端设置响应头Content-type
为text/event-stream
。
java简单代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| @WebServlet(urlPatterns = "/streaming",asyncSupported = true) public static class StreamingServlet extends HttpServlet {
private static final long serialVersionUID = 1L; private ExecutorService executorService = Executors.newCachedThreadPool();
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/event-stream"); response.setCharacterEncoding("UTF-8"); final AsyncContext asyncContext = request.startAsync(); executorService.execute(() -> { try { PrintWriter writer = response.getWriter(); for (int i = 0; i < 10; i++) { writer.write("data: " + i + "\n\n"); writer.flush();
Thread.sleep(1000); } } catch (IOException | InterruptedException e) { e.printStackTrace(); } finally { asyncContext.complete(); } }); } @Override public void destroy() { executorService.shutdown(); } }
|
效果
AsyncContext
看到别人实现sse时都使用的AsyncContext,但是并不知道有啥用,查询资料后得知
使用final AsyncContext asyncContext = request.startAsync();
可以实现Servlet 线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,等待异步线程任务结束后可以直接生成响应数据。