当前位置:网站首页>Practice of real-time push demo of three web messages: long polling, iframe and SSE
Practice of real-time push demo of three web messages: long polling, iframe and SSE
2022-07-28 20:16:00 【Fire king】
Long polling ,iframe and sse Three web Message push in real time demo practice
Long polling
@Controller
@RequestMapping("/polling")
public class PollingController {
private static final Long TIME_OUT = 10000l;
// Store and monitor a Id Long polling set for
// Thread synchronization structure
public static Multimap<String, DeferredResult<String>> watchRequests = Multimaps.synchronizedMultimap(HashMultimap.create());
/** * * Set listening */
@GetMapping(path = "watch/{id}")
@ResponseBody
public DeferredResult<String> watch(@PathVariable String id) {
// Delay object setting timeout
DeferredResult<String> deferredResult = new DeferredResult<>(TIME_OUT);
// Remove when the asynchronous request completes key, Prevent memory overflow
deferredResult.onCompletion(() -> {
watchRequests.remove(id, deferredResult);
});
// Registrar polling request
watchRequests.put(id, deferredResult);
return deferredResult;
}
/** * * Change data */
@GetMapping(path = "publish/{id}")
@ResponseBody
public String publish(@PathVariable String id) {
// Data changes Take out the monitor ID All long polling requests ( Multiple browsers , Different windows of a single browser only think of one , Every time publish Just change one ), And respond one by one
if (watchRequests.containsKey(id)) {
Collection<DeferredResult<String>> deferredResults = watchRequests.get(id);
System.out.println(deferredResults.size());
for (DeferredResult<String> deferredResult : deferredResults) {
// as long as set, Think it's changed
deferredResult.setResult(" I updated " + new Date());
}
}
return "success";
}
// When the request exceeds the set timeout , Will throw out AsyncRequestTimeoutException abnormal , It's directly used here @ControllerAdvice Global capture and unified return , After obtaining the agreed status code, the front end sends a long polling request again , Call back and forth like this .
@ControllerAdvice
public class AsyncRequestTimeoutHandler {
@ResponseStatus(HttpStatus.NOT_MODIFIED)
@ResponseBody
@ExceptionHandler(AsyncRequestTimeoutException.class)
public String asyncRequestTimeoutHandler(AsyncRequestTimeoutException e) {
System.out.println(" Asynchronous request timed out ");
return "304";
}
}
}
iframe
IframeController
@Controller
@RequestMapping("/iframe")
public class IframeController {
@GetMapping(path = "message")
public void message(HttpServletResponse response) throws IOException, InterruptedException {
int count = 0;
while (true) {
count++;
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache,no-store");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().print(" <script type=\"text/javascript\">\n" +
"parent.document.getElementById('clock').innerHTML = \"" + count + "\";" +
"parent.document.getElementById('count').innerHTML = \"" + count + "\";" +
"</script>");
}
}
@GetMapping(path = "toIframePage")
public String toIframePage() {
return "/iframe";
}
}
iframe.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>iframe Long polling </title>
</head>
<body>
<iframe src="/iframe/message" style="display:none"></iframe>
<h1 id="clock"></h1>
<h1 id="count"></h1>
</body>
</html>
sse
SseEmitterServer
@Slf4j
public class SseEmitterServer {
private static Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();
/** * Current connections */
private static AtomicInteger count = new AtomicInteger(0);
/** * Create connection * * @date: 2022/7/12 14:51 * @auther: */
public static SseEmitter connect(String userId) {
try {
// Set timeout ,0 No expiration date . Default 30 second
SseEmitter sseEmitter = new SseEmitter(0L);
// Register callback
sseEmitter.onCompletion(completionCallBack(userId));
sseEmitter.onError(errorCallBack(userId));
sseEmitter.onTimeout(timeoutCallBack(userId));
sseEmitterMap.put(userId, sseEmitter);
count.getAndIncrement();
return sseEmitter;
} catch (Exception e) {
log.info(" Create a new sse Abnormal connection , The current user :{}", userId);
}
return null;
}
private static Consumer<Throwable> errorCallBack(String userId) {
return throwable -> {
log.info(" Abnormal connection :{}", userId);
removeUser(userId);
};
}
private static Runnable timeoutCallBack(String userId) {
return () -> {
log.info(" Connection timeout :{}", userId);
removeUser(userId);
};
}
private static Runnable completionCallBack(String userId) {
return () -> {
log.info(" End connection :{}", userId);
removeUser(userId);
};
}
public static void removeUser(String userId) {
sseEmitterMap.remove(userId);
// Number -1
count.getAndDecrement();
log.info(" Remove users :{}", userId);
}
/** * Send a message to the specified user * * @date: 2022/7/12 14:51 * @auther: */
public static void sendMessage(String userId, String message) {
if (sseEmitterMap.containsKey(userId)) {
try {
sseEmitterMap.get(userId).send(message);
// Different SpringBoot The version of may need to add
// sseEmitterMap.get(userId).complete();
} catch (IOException e) {
log.error(" user [{}] Push exception :{}", userId, e.getMessage());
removeUser(userId);
}
}
}
}
SseEmitterController
@CrossOrigin
@RestController
@RequestMapping("/sse")
public class SseEmitterController {
/** * Used to create a connection */
@GetMapping("/connect/{userId}")
public SseEmitter connect(@PathVariable String userId) {
return SseEmitterServer.connect(userId);
}
/** * Push to everyone * * @param message * @return */
/* @GetMapping("/push/{message}") public ResponseEntity<String> push(@PathVariable(name = "message") String message) { SseEmitterServer.batchSendMessage(message); return ResponseEntity.ok("WebSocket Push messages to everyone "); }*/
/** * Send to a single person * * @param message * @param userid * @return */
@RequestMapping("/push_one")
public ResponseEntity<String> pushOne( String message, String userid) {
SseEmitterServer.sendMessage(userid, message);
return ResponseEntity.ok("WebSocket Push a message to " + userid);
}
/** * Close the connection */
@GetMapping("/close/{userid}")
public ResponseEntity<String> close(@PathVariable("userid") String userid) {
SseEmitterServer.removeUser(userid);
return ResponseEntity.ok(" Connection is closed ");
}
}
PageController
@Controller
public class PageController {
@RequestMapping("/toSsePage")
public String toSsePage() {
return "/sse";
}
}
sse.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SseEmitter</title>
</head>
<body>
<button onclick="closeSse()"> Close the connection </button>
<div id="message"></div>
</body>
<script> let source = null; // Simulate login user with timestamp //const userId = new Date().getTime(); const userId = "1"; if (window.EventSource) {
// Establishing a connection source = new EventSource('http://localhost:8080/sse/connect/' + userId); /** * Once the connection is established , It will trigger open event * Another way of writing :source.onopen = function (event) {} */ source.addEventListener('open', function(e) {
setMessageInnerHTML(" Establishing a connection ..."); }, false); /** * The client receives the data from the server * Another way of writing :source.onmessage = function (event) {} */ source.addEventListener('message', function(e) {
setMessageInnerHTML(e.data); }); /** * If a communication error occurs ( For example, the connection is broken ), It will trigger error event * perhaps : * Another way of writing :source.onerror = function (event) {} */ source.addEventListener('error', function(e) {
if (e.readyState === EventSource.CLOSED) {
setMessageInnerHTML(" Connection is closed "); } else {
console.log(e); } }, false); } else {
setMessageInnerHTML(" Your browser does not support it SSE"); } // Listen for window closing events , Active close sse Connect , If the server settings never expire , After the browser is closed, manually clean up the server data window.onbeforeunload = function() {
closeSse(); }; // close Sse Connect function closeSse() {
source.close(); const httpRequest = new XMLHttpRequest(); httpRequest.open('GET', 'http://localhost:8080/sse/close/' + userId, true); httpRequest.send(); console.log("close"); } // Displays the message on the web page function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>'; } </script>
</html>
Advantages and disadvantages of the above three message push
边栏推荐
- [C language] shutdown game [loop and switch statement]
- Why is there no log output in the telnet login interface?
- How to use pycharm to quickly create a flask project
- C language - data storage
- C language function
- The results of the second quarter online moving people selection of "China Internet · moving 2022" were announced
- Communication learning static routing across regional networks
- 进制及数的表示 2
- 通信网络基础知识01
- Why is customer support important to SaaS?
猜你喜欢

数字滤波器设计——Matlab

What is the variance?

Deploy LNMP automatically with saltstack

Saltstack advanced
![最大交换[贪心思想&单调栈实现]](/img/ad/8f0914f23648f37e1d1ce69086fd2e.png)
最大交换[贪心思想&单调栈实现]

Basic usage of docker

Intermediate soft test (system integration project management engineer) high frequency test site

Theoretical knowledge of digital image (I) (personal analysis)

83. (cesium home) how the cesium example works

Merge sort template
随机推荐
Implementation of strstr in C language
长轮询,iframe和sse三种web消息实时推送demo实践
Token verification program index.php when configuring wechat official account server
Scene thread allocation in MMO real-time combat games
Deploy LNMP automatically with saltstack
English translation Italian - batch English translation Italian tools free of charge
C language function
Communication learning static routing across regional networks
Implementation of memmove in C language
9. Pointer of C language (2) wild pointer, what is wild pointer, and the disadvantages of wild pointer
私有化部署的即时通讯平台,为企业移动业务安全保驾护航
The results of the second quarter online moving people selection of "China Internet · moving 2022" were announced
C language pointer and two-dimensional array
Basic knowledge of C language
[C language] scanf format input and modifier summary
【实验分享】CCIE—BGP反射器实验
熊市下PLATO如何通过Elephant Swap,获得溢价收益?
Array method added in ES6
Stories of Party members | Li qingai uses cartoons to drive farmers to increase income and become rich
CDGA|工业互联网行业怎么做好数据治理?