导言

运用Java开发web应用,大多数时候我们供给的接口回来数据都是一次性完整回来。有些时候,我们也需求供给流式接口持续写出数据,以下供给一种简略的方式。

SSE(Server-Sent Events)

SSE 是一种答应服务器单向发送事情到客户端的技能,它根据HTTP协议,服务器能够推送消息到客户端,但客户端不能向服务器发送消息。

完成

直接上代码

@RestController
public class TestController {
    private static final Logger logger = LoggerFactory.getLogger(TestController.class);
    @GetMapping("/test")
    public void test(HttpServletResponse response) {
        response.setContentType("text/event-stream");
        response.setCharacterEncoding("utf-8");
        try (final PrintWriter writer = response.getWriter()) {
            // 要推送的内容
            final String content = "你好,我的朋友,快过年了,提早祝你新年快乐!";
            int len = content.length();
            int endIndex = 0;
            // 每隔2个字符推送一次,模拟打字机效果
            while (endIndex < len) {
                endIndex = Math.min(endIndex + 2, len);
                final String subContent = content.substring(0, endIndex);
                // 将要推送的内容封装成JSON格局,模拟实践开发中的数据格局,非有必要
                final JSONObject json = new JSONObject();
                json.put("data", subContent);
                json.put("code", HttpStatus.OK.value());
                // 最终一次推送时,type为finish,表示推送结束,其它状况为add
                final String type = endIndex == len
                        ? "finish"
                        : "add";
                json.put("type", type);
                // 拼装成SSE格局的数据,发送给前端,这个格局(data: contentnn)是固定的,content是自定义的推送内容
                writer.write("data: " + json.toJSONString() + "nn");
                writer.flush();
                // 略微给点中止,避免数据发送太快,浏览器接纳不过来
                TimeUnit.MILLISECONDS.sleep(100);
            }
        } catch (Exception e) {
            Thread.currentThread().interrupt();
            logger.error("流式推送数据异常", e);
        }
    }
}

拼装数据,格局固定为"data: " + content + "nn",这里的数据格局是服务器发送事情(Server-Sent Events,SSE)的标准格局。

SSE 中,数据有必要以 "data: " 最初,然后是要发送的数据,最终是两个换行符"nn"。这是SSE的规则格局,客户端会根据这种格局来解析服务器发送的事情。

接口调试

用接口调试工具(我用的是Apifox)调试接口如下:

运用Java和Spring Boot完成服务器发送事情(Server-Sent Events)

接口契合SSE标准,所以能够被正常识别为事情流推送。

SSE与其他实时通讯技能的比较

SSE与WebSocket的比较

  • 通讯方式:SSE是单向的,只能由服务器向客户端发送数据;而WebSocket是双向的,服务器和客户端都能够发送数据。
  • 协议:SSE根据HTTP协议,更易于设置和装备;WebSocket是一个独立的协议。
  • 数据格局:SSE发送的数据格局固定,有必要是”text/event-stream”;而WebSocket能够发送任何类型的数据。
  • 衔接:SSE在断开衔接后能够自动重新衔接,而WebSocket需求手动处理重连。
  • 浏览器支撑:WebSocket的浏览器支撑更广泛,几乎所有现代浏览器都支撑WebSocket;而SSE在某些旧版本的浏览器(如IE)中不被支撑。

SSE与长轮询的比较

  • 效率:SSE更高效,因为它只需求一个HTTP衔接,就能够持续地发送数据;而长轮询需求不断地树立和断开HTTP衔接。
  • 实时性:SSE的实时性更强,因为服务器能够随时发送数据;而长轮询需求客户端不断地发送请求来获取新数据。
  • 复杂性:SSE的完成相对简略,只需求服务器按照规则的格局发送数据即可;而长轮询的完成较复杂,需求处理衔接的树立和断开,以及过错和超时等问题。
  • 浏览器支撑:与WebSocket相比,SSE和长轮询的浏览器支撑都较差,但长轮询在更多的浏览器中被支撑。
  • 适用场景:SSE适用于服务器需求自动推送数据的场景;而长轮询适用于客户端需求定时获取新数据,但服务器不需求自动推送数据的场景。

注意事项

  • 以上一个简略的事情流推送接口就完成好了,但是它的问题是客户端无法干涉服务器的推流,如果需求半途停止接纳内容,根据以上接口是无法做到的。所以实践项目开发过程中,能够运用Spring框架供给的SseEmitter,详细用法能够参阅 轻松完成服务器事情推送!Spring SseEmitter 详解
  • 浏览器支撑:并非所有浏览器都支撑SSE,例如,旧版本的Internet Explorer就不支撑SSE。在运用SSE时,需求确保目标用户的浏览器支撑这项技能。
  • 衔接约束:由于SSE需求坚持长衔接,因此可能会占用大量的服务器资源。在运用SSE时,需求考虑到这一点,并根据实践状况进行优化。