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."));
    })      
          
    

    参考资料

  • 相关阅读:
    CSS同时选择器
    create-react-app之proxy
    mysql limit语句
    给tbody加垂直滚动条的具体思路
    MySql数据类型范围
    block、inline、inline-block
    javascript sourcemap
    session of express
    React中innerHTML的坑
    box-sizing
  • 原文地址:https://www.cnblogs.com/wei57960/p/12372232.html
Copyright © 2011-2022 走看看