SSE服务器推送技术

作者: elijah777 | 来源:发表于2019-06-30 23:37 被阅读17次

SSE即 server send event 服务器发送事件,在在早期可能会使用ajax向服务器轮询的方式,使浏览器第一时间接受到服务器的消息,但这种频率不好控制,消耗也比较大。

但是对于SSE来说,当客户端向服务端发送请求,服务端会抓住这个请求不放,等到有数据时才返回给客户端,但客户端手动消息后,再向服务器发送请求,周而复始。这种方式好处是减少了服务器的请求数量,也大大减少了服务器的压力。

以下是第一种方式的代码的演示,浏览器不断向服务器请求,服务器用线程睡眠5s再返回结果。

1、SseController 控制器

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Random;
​
/**
 * @description: 服务器端推送控制器
 *
 * @author: Shenshuaihu
 * @version: 1.0
 * @data: 2019-06-25 23:29
 */
@Controller
public class SseController {
​
 /**
 * 输出类型 text/event-stream 是对服务器端SSE的支持
 * 此处每5s向浏览器推送随机消息
 * @return
 */
 @RequestMapping(value = "/push", produces = "text/event-stream")
 public @ResponseBody String push() {
 Random random = new Random();
 try {
 Thread.sleep(5000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 return "data:Testing 1,2,3: " + random.nextInt() + "\n\n";
 }
}

2、显示结果的页面 sse.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
 <title>SSE-Code</title>
 <link rel="stylesheet" type="text/css" value="">
</head>
<body>
<h2> sse.jsp </h2>
​
服务器推送  可以用于消息订阅
<br/>
解决长短轮询不是解决问题
<br/>
server send event 当客户端方服务器发送请求时 服务器抓住不放 等有数据时 再回复给客户端,客户端收到消息时发给送给服务器,如此循环
<br/>
参考内容:
https://www.jianshu.com/p/bc5a9b4a1cd1
​
<div id="msgFromPush"></div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
​
<script>
 console.log("!!Window EventSource: " + !!Window.EventSource)
 if (!!window.EventSource) {
 var source = new EventSource('push');
 s = '';
 source.addEventListener('message', function (evt) {
 s += evt.data + "<br/>";
 $("#msgFromPush").html(s);
 });
​
 source.addEventListener('open', function (evt) {
 console.log("连接打开.")
 })
​
 // 添加SSE客户端监听,获取服务端推送的消息
 source.addEventListener('error', function (evt) {
 if (evt.readyState == EventSource.CLOSED) {
 console.log("连接关闭.")
 } else {
 console.log(evt.readyState)
 }
 }, false);
​
 } else {
 console.log("你的浏览器不支持SSE.")
 }
​
​
 /*if(window.EventSource){
​
 var eventSource = new EventSource("http://localhost:8080/push");
​
 //只要和服务器连接,就会触发open事件
 eventSource.addEventListener("open",function(){
 console.log("和服务器建立连接");
 });
​
 //处理服务器响应报文中的load事件
 eventSource.addEventListener("load",function(e){
 console.log("服务器发送给客户端的数据为:" + e.data);
 });
​
 //如果服务器响应报文中没有指明事件,默认触发message事件
 eventSource.addEventListener("message",function(e){
 console.log("服务器发送给客户端的数据为:" + e.data);
 });
​
 //发生错误,则会触发error事件
 eventSource.addEventListener("error",function(e){
 console.log("服务器发送给客户端的数据为:" + e.data);
 });
​
 }
 else{
 console.log("服务器不支持EvenSource对象");
 }*/
​
</script>
</body>
</html>

显示的结果

SSE-.png

二、使用Servlet 3.0 + 异步方法处理,第二种方式演示,浏览器循环请求服务端,服务端用定时任务,每5S设置一下数据,返回给浏览器

1、开启异步方法的支持 WebInitializer.java

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
​
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
​
/**
 * @description: Web配置 代替web.xml
 * @author: Shenshuaihu
 * @version: 1.0
 * @data: 2019-06-13 23:22
 */
public class WebInitializer implements WebApplicationInitializer {
 @Override
 public void onStartup(ServletContext servletContext) throws ServletException {
 AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
 context.register(MyMvcConfig.class);
 // 新建的webApplicationContext ,注册配置类,并将其和当前servletContext关联。
 context.setServletContext(servletContext);
​
 // 注册SpringMVC 的 DispatcherServlet
 Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));
 servlet.addMapping("/");
 servlet.setLoadOnStartup(1);
 // 开启对异步的支持
 servlet.setAsyncSupported(true);
 }
}

2、AsyncController.java 控制层,只用掉service

import com.ch4.service.PushService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;
​
/**
 * @description:
 *
 * @author: Shenshuaihu
 * @version: 1.0
 * @data: 2019-06-27 08:32
 */
@Controller
public class AsyncController {
 @Autowired
 private PushService pushService;
​
 @RequestMapping("/defer")
 @ResponseBody
 public DeferredResult<String> deferredCall() {
 return pushService.getAsyncUpdate();
 }
}

3、PushService.java

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;
​
/**
 * @description: SSE 定时任务
 *      在PushService里面产生 DeferredResult 给控制器使用,
 *      通过 @Scheduled 定时更新DeferredResult
 *
 * @author: Shenshuaihu
 * @version: 1.0
 * @data: 2019-06-27 08:32
 */
@Service
public class PushService {
​
 private DeferredResult<String> deferredResult;
​
 public DeferredResult<String> getAsyncUpdate() {
 deferredResult = new DeferredResult<String>();
 return deferredResult;
 }
​
 @Scheduled(fixedDelay = 5000)
 public void refresh() {
 if (deferredResult != null) {
 deferredResult.setResult(new Long(System.currentTimeMillis()).toString());
 }
 }
}

3、数据页面async.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<title>async support-Code</title>
<link rel="stylesheet" type="text/css" value="">
</head>
<body>
<h2> defer.jsp </h2>
​
​
​
<div id="defer"></div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
​
<script>
​
deferred();
​
function deferred() {
$.get('defer', function (data) {
console.log(data);
s = '';
s += data + "<br/>";
$('#defer').html(s)
// 完成后在向服务器请求
deferred();
}
​
);
}
​
</script>
</body>
</html>

4、需要在核销配置类用开启任务

@Configuration
@EnableWebMvc
@ComponentScan("com.ch4")
@EnableScheduling
public class MyMvcConfig extends WebMvcConfigurerAdapter {}
SSE-aync.png

总结:

SSE用于订阅消息,是需要浏览器不断的请求,与websocket有相似之处

2019/06/30晚于成都

相关文章

网友评论

    本文标题:SSE服务器推送技术

    本文链接:https://www.haomeiwen.com/subject/ecbicctx.html