zoukankan      html  css  js  c++  java
  • 客户端接收消息的几种方式

    前言

    系统的业务中,网页需要弹窗"报警信息"。前端获取数据的方式通过轮询调后端接口。也考虑过WebSocket 的方式,但好像兼容性不太好。现在发现还有其他更优的方式,在此记录一下。

    网页端收服务端的消息的方式

    一、轮询拉取

    客户端间隔的发送ajax请求服务器的数据。

    • 优点:实现简单
    • 缺点:
      • 实时性比较差,最大时差就是前端的间隔
      • 效率低:如果长时间没有消息,客户端还是在轮询请求。浪费服务端的资源
    二、建立长连接
    • 如果要兼顾实时性和效率,长连接是最佳之选,PC端聊天软件基本都是使用长连接。网页端常见的实现长连接的方式有两种:WebSocket和FlashSocket
    • 缺点:兼容性差,有些浏览器不支持
    三、Http长轮询 (通用方式)

    通过HTTP短连接拼装长连接,具体是通过“夯住”“只收推送通知”的“通知连接”来实现的,能够做到消息的实时性到达。

    客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求

    在浏览器和服务端建立了一条"通知连接"的特点:

    • 这是一条browser发往web-server的HTTP连接
    • 这条连接只用来收取推送通知
    • 不像普通的“请求-响应”式HTTP请求,这个HTTP会被服务端夯住,直到有推送通知到达,或者超过约定的时间

    对于HTTP请求,为了提高效率,一般来说browser和web-server都会有一些设置,如果一条HTTP请求长时间没有数据(例如,150秒),会被断开。“通知连接”为了不被browser和web-server粗暴断开,一般会设置一个约定阈值(例如,小于150秒),由系统返回一个空消息,以便“优雅返回”。

    浏览器发起通知连接时,如果服务端的队列里面有消息,则服务端立刻把消息返回。如果这条连接达到了"约定阈值"要断开时,服务端返回空消息维持连接。当服务端返回消息(空的或者真实消息)的同时,浏览器会瞬间再发起连接。在消息过去和浏览器返回的时间差时有消息时,服务端将新的消息放入队列(发生概率很小)

    • 缺点:服务器hold连接会消耗资源
    实现Http长轮询

    使用 DeferredResult 异步请求处理

    @GetMapping("/async-deferredresult")
    public DeferredResult<ResponseEntity<?>> handleReqDefResult(Model model) {
        LOG.info("Received async-deferredresult request");
        DeferredResult<ResponseEntity<?>> output = new DeferredResult<>();
         
        ForkJoinPool.commonPool().submit(() -> {
            LOG.info("Processing in separate thread");
            try {
                Thread.sleep(6000); // 模拟延迟六秒返回
            } catch (InterruptedException e) {
            }
            output.setResult(ResponseEntity.ok("ok"));
        });
         
        LOG.info("servlet thread freed");
        return output;
    }
    
    
    // 设置超时,即在后端一致没有数据的情况下,多长时间断开连接。使用的是onTimeout()方法。
    deferredResult.onTimeout(() -> 
      deferredResult.setErrorResult(
        ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT)
          .body("Request timeout occurred.")));
          
     
     // 如果后端出现了错误,可以设置onError()方法修改返回状态码:     
    deferredResult.onError((Throwable t) -> {
        deferredResult.setErrorResult(
          ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body("An error occurred."));
    })      
          
    

    参考资料

  • 相关阅读:
    Interview with BOA
    Java Main Differences between HashMap HashTable and ConcurrentHashMap
    Java Main Differences between Java and C++
    LeetCode 33. Search in Rotated Sorted Array
    LeetCode 154. Find Minimum in Rotated Sorted Array II
    LeetCode 153. Find Minimum in Rotated Sorted Array
    LeetCode 75. Sort Colors
    LeetCode 31. Next Permutation
    LeetCode 60. Permutation Sequence
    LeetCode 216. Combination Sum III
  • 原文地址:https://www.cnblogs.com/wei57960/p/12372232.html
Copyright © 2011-2022 走看看