使用HTTP/2实现服务端主动推送消息给客户端

这篇具有很好参考价值的文章主要介绍了使用HTTP/2实现服务端主动推送消息给客户端。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

77. 使用HTTP/2实现服务端主动推送消息给客户端

HTTP/2协议的服务器主动推送机制是通过服务器在接收到客户端请求后,主动向客户端推送相关资源的方式来实现的。下面将详细解释如何在服务器端和客户端实现HTTP/2的服务器主动推送,并给出相应的代码示例。

客户端实现:

前端使用EventSource对象订阅/api/subscribe接口,监听服务器发送的事件。

const eventSource = new EventSource('/api/subscribe');

eventSource.onmessage = event => {
  const data = JSON.parse(event.data);
  console.log('Received data:', data);

  // 判断接收到的数据是否是最终结果
  if (data.status === 'completed') {
    // 停止订阅
    eventSource.close();
  }
};

eventSource.onerror = error => {
  console.error('SSE error:', error);
};
服务器端实现:

后端在接收到订阅请求后,先使用stream.pushStream()方法向客户端推送中间结果,然后再模拟等待一段时间后返回最终结果。

const http2 = require('http2');
const fs = require('fs');

// 创建HTTP/2服务器
const server = http2.createSecureServer({
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
});

// 处理订阅请求
server.on('stream', (stream, headers) => {
  // 模拟等待特定操作的时间
  setTimeout(() => {
    // 推送中间结果给客户端
    stream.pushStream({ ':path': '/api/subscribe' }, (pushStream) => {
      pushStream.respond({
        'content-type': 'application/json',
        ':status': 200
      });
      pushStream.end(JSON.stringify({ status: 'processing' }));
    });

    // 模拟等待更长时间后返回最终结果
    setTimeout(() => {
      stream.respond({
        'content-type': 'application/json',
        ':status': 200
      });
      stream.end(JSON.stringify({ status: 'completed', result: 'Operation completed' }));
    }, 5000); // 等待5秒钟
  }, 2000); // 等待2秒钟
});

// 监听端口
server.listen(3000, () => {
  console.log('Server started on port 3000');
});

通过结合长轮询和HTTP/2的服务器推送,可以实现前端请求接口后等待一段时间,直到后端执行了特定操作后再将结果返回给前端的需求。

请注意,上述示例代码仅为演示目的,并未考虑错误处理、安全性等方面的细节。在实际应用中,需要根据具体情况进行适当的调整和优化。

每日一游 - 贪吃蛇小游戏

使用HTTP/2实现服务端主动推送消息给客户端文章来源地址https://www.toymoban.com/news/detail-500256.html

<html>
<head>
  <title>贪吃蛇游戏</title>
  <style>
    /* 游戏画布样式 */
    #game-canvas {
      width: 400px;
      height: 400px;
      border: 1px solid black;
      position: relative;
    }
    
    /* 蛇身和食物样式 */
    .snake-segment {
      width: 20px;
      height: 20px;
      background-color: green;
      position: absolute;
    }
    
    .food {
      width: 20px;
      height: 20px;
      background-color: red;
      position: absolute;
    }
  </style>
</head>
<body>
  <h1>贪吃蛇游戏</h1>
  
  <div id="game-canvas"></div>

  <div>
    <p>得分:<span class="score">0</span></p>
    <button id="restart-button">重新开始</button>
  </div>
  
  <script>

    // 获取游戏画布元素
    const gameCanvas = document.getElementById('game-canvas');
    
    // 定义游戏画布的宽度和高度
    const canvasWidth = 400;
    const canvasHeight = 400;
    
    // 定义蛇身的尺寸和初始位置
    const segmentSize = 20;
    let snakeSegments = [
      { x: segmentSize * 3, y: 0 },
      { x: segmentSize * 2, y: 0 },
      { x: segmentSize, y: 0 }
    ];

    // 随机生成初始位置
    const initialX = Math.floor(Math.random() * (canvasWidth / segmentSize - 3) + 3) * segmentSize;
    const initialY = Math.floor(Math.random() * (canvasHeight / segmentSize)) * segmentSize;

    
    // 定义蛇的初始移动方向
    let direction = 'right';
    
    // 定义食物的初始位置
    let food = { x: 200, y: 200 };
    
    // 创建蛇身元素和食物元素
    function createSegmentElement(x, y) {
      const segment = document.createElement('div');
      segment.className = 'snake-segment';
      segment.style.left = x + 'px';
      segment.style.top = y + 'px';
      return segment;
    }
    
    function createFoodElement(x, y) {
      const foodElement = document.createElement('div');
      foodElement.className = 'food';
      foodElement.style.left = x + 'px';
      foodElement.style.top = y + 'px';
      return foodElement;
    }
    
    // 更新蛇身的位置
    function updateSnakePosition() {
      const segments = document.getElementsByClassName('snake-segment');
      for (let i = 0; i < snakeSegments.length; i++) {
        segments[i].style.left = snakeSegments[i].x + 'px';
        segments[i].style.top = snakeSegments[i].y + 'px';
      }
    }
    
    // 更新食物的位置
    function updateFoodPosition() {
      const foodElement = document.querySelector('.food');
      foodElement.style.left = food.x + 'px';
      foodElement.style.top = food.y + 'px';
    }
    
    // 清除画布
    function clearCanvas() {
      gameCanvas.innerHTML = '';
    }
    
    // 绘制蛇身
    function drawSnake() {
      snakeSegments.forEach(segment => {
        const segmentElement = createSegmentElement(segment.x, segment.y);
        gameCanvas.appendChild(segmentElement);
      });
    }
    
    // 绘制食物
    function drawFood() {
      const foodElement = createFoodElement(food.x, food.y);
      gameCanvas.appendChild(foodElement);
    }

    // 显示得分
    function getScore() {
      const scoreText = document.querySelector(".score")
      scoreText.innerText = snakeSegments.length - 3
    }
    
    // 移动蛇的函数
    function moveSnake() {
      // 创建新的蛇头
      const head = { x: snakeSegments[0].x, y: snakeSegments[0].y };
      
      // 根据方向更新蛇头的位置
      switch (direction) {
        case 'up':
          head.y -= segmentSize;
          break;
        case 'down':
          head.y += segmentSize;
          break;
        case 'left':
          head.x -= segmentSize;
          break;
        case 'right':
          head.x += segmentSize;
          break;
      }
      
      // 将新的蛇头插入到蛇身数组的第一个位置
      snakeSegments.unshift(head);
      
      // 检查是否吃到食物
      if (head.x === food.x && head.y === food.y) {
        // 生成新的食物位置
        initFoodPosition();
      } else {
        // 如果没有吃到食物,移除蛇身数组的最后一个元素,即蛇尾
        snakeSegments.pop();
      }
      
      // 清除画布
      clearCanvas();
      
      // 绘制蛇身和食物
      drawSnake();
      drawFood();
      
      // 实时分数更新
      getScore()


      // 检查游戏是否结束
      if (isCollision()) {
        clearInterval(gameLoop);
        alert('游戏结束!得分:' + (snakeSegments.length - 3));
      }
    }
    
    // 检查蛇头是否与蛇身或游戏边界发生碰撞
    function isCollision() {
      const head = snakeSegments[0];
      
      // 检查是否与蛇身碰撞
      for (let i = 1; i < snakeSegments.length; i++) {
        if (head.x === snakeSegments[i].x && head.y === snakeSegments[i].y) {
          return true;
        }
      }
      
      // 检查是否与游戏边界碰撞
      if (
        head.x < 0 ||
        head.x >= canvasWidth ||
        head.y < 0 ||
        head.y >= canvasHeight
      ) {
        return true;
      }
      
      return false;
    }
    
    // 监听键盘按键事件,改变蛇的移动方向
    document.addEventListener('keydown', function(event) {
      switch (event.key) {
        case 'ArrowUp':
          if (direction !== 'down') {
            direction = 'up';
          }
          break;
        case 'ArrowDown':
          if (direction !== 'up') {
            direction = 'down';
          }
          break;
        case 'ArrowLeft':
          if (direction !== 'right') {
            direction = 'left';
          }
          break;
        case 'ArrowRight':
          if (direction !== 'left') {
            direction = 'right';
          }
          break;
      }
    });
    
    // 初始化食物位置
    function initFoodPosition() {
      let validPosition = false;
      while (!validPosition) {
        food.x = Math.floor(Math.random() * (canvasWidth / segmentSize)) * segmentSize;
        food.y = Math.floor(Math.random() * (canvasHeight / segmentSize)) * segmentSize;
        
        // 检查食物位置是否与蛇身重叠
        let overlap = false;
        for (let i = 0; i < snakeSegments.length; i++) {
          if (food.x === snakeSegments[i].x && food.y === snakeSegments[i].y) {
            overlap = true;
            break;
          }
        }
        
        if (!overlap) {
          validPosition = true;
        }
      }
    }
    
    // 获取重新开始按钮元素
    const restartButton = document.getElementById('restart-button');

    // 重新开始游戏
    function restartGame() {
      clearInterval(gameLoop); // 清除游戏循环
      snakeSegments = [
        { x: segmentSize * 3, y: 0 },
        { x: segmentSize * 2, y: 0 },
        { x: segmentSize, y: 0 }
      ]; // 重置蛇身位置
      direction = 'right'; // 重置蛇的移动方向
      initFoodPosition(); // 重新生成食物位置
      clearCanvas(); // 清除画布
      drawSnake(); // 绘制蛇身
      drawFood(); // 绘制食物
      gameLoop = setInterval(moveSnake, 500); // 启动游戏循环
    }

    // 监听重新开始按钮的点击事件
    restartButton.addEventListener('click', restartGame);


    // 初始化游戏
    function initGame() {
      // 生成初始的食物位置
      initFoodPosition();
      
      // 将蛇身元素和食物元素添加到游戏画布中
      drawSnake();
      drawFood();
      
      // 启动游戏循环
      gameLoop = setInterval(moveSnake, 200);
    }
    
    // 开始游戏
    initGame();

  </script>
</body>
</html>

到了这里,关于使用HTTP/2实现服务端主动推送消息给客户端的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android 实现MQTT客户端,用于门禁消息推送

    添加MQTT依赖 implementation ‘org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.2’ implementation ‘org.eclipse.paho:org.eclipse.paho.android.service:1.1.1’ 在Manifest清单文件中添加服务 MqttClient的实现方式 MQTT初始化连接线程,实现与服务器的连接、订阅、发布消息 MQTT重连 MQTT断开 发送消息 MqttAndroid

    2024年02月14日
    浏览(52)
  • HTTP介绍 原理 消息结构 客户端请求 服务器响应 HTTP状态码

    HTTP协议 是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(www.world wide web)服务器传输超文本到本地浏览器的传送协议 HTTP 是基于TCP/IP(三次握手,四次挥手)通信协议来传输数据(HTML文件,图片文件,查询结果等) TCP:可靠的,丢包重传 UTP:不可靠的,直播,

    2024年02月05日
    浏览(55)
  • 【Java】SpringBoot快速整合WebSocket实现客户端服务端相互推送信息

    目录 什么是webSocket? webSocket可以用来做什么? WebSocket操作类 一:测试客户端向服务端推送消息 1.启动SpringBoot项目 2.打开网站 3.进行测试消息推送 4.后端进行查看测试结果 二:测试服务端向客户端推送消息 1.接口代码 2.使用postman进行调用 3.查看测试结果         WebSocke

    2024年01月20日
    浏览(62)
  • springboot集成webstock实战:服务端数据推送数据到客户端实现实时刷新

        之前介绍过springboot集成webstock方式,具体参考: springboot集成websocket实战:站内消息实时推送 这里补充另外一个使用webstock的场景,方便其他同学理解和使用,废话不多说了,直接开始!简单介绍一下业务场景:     现在有一个投票活动,活动详情中会显示投票活动的参与人数、访

    2024年02月08日
    浏览(98)
  • Thinkphp5.0 安装使用Workerman实现websocket前后端通信,后端主动推送消息到前端

    安装使用Workerman实现websocket前后端通信,后端主动推送消息到前端,实现后端有数据更新时,前端页面自动更新数据。 我使用的是基于Thinkphp5.0的ThinkCMF5.0。 安装: 启动: public目录下放置的server.php文件,注意里面的配置必须按照你的Worker控制器来: woker控制器: 后端主动推

    2024年02月16日
    浏览(55)
  • Qt实现客户端与服务器消息发送

    里用Qt来简单设计实现一个场景,即: (1)两端:服务器QtServer和客户端QtClient (2)功能:服务端连接客户端,两者能够互相发送消息,传送文件,并且显示文件传送进度。 环境:VS20013 + Qt5.11.2 + Qt设计师 先看效果: 客户端与服务器的基本概念不说了,关于TCP通信的三次握

    2024年02月11日
    浏览(51)
  • Springboot整合WebSocket实现主动向前端推送消息

            在上篇文章tcp编程中,我们实现了C++客户端与java服务器之间的通信,客户端发送了一个消息给服务器,今天我们要实现基于WebSocket实现服务器主动向前端推送消息,并且以服务器接收到C++客户端的消息主动向前端推送消息的触发条件。 WebSocket 的诞生背景       

    2024年03月16日
    浏览(43)
  • Java 构建websocket客户端,构建wss客户端,使用wss连接,并发送数据到服务器端,接收服务器端消息

    Java 构建websocket客户端,构建wss客户端,使用wss连接,并发送数据到服务器端,接收服务器端消息 回调函数处理

    2024年02月13日
    浏览(61)
  • 服务器端使用django websocket,客户端使用uniapp 请问服务端和客户端群组互发消息的代码怎么写的参考笔记

    2023/8/29 19:21:11 服务器端使用django websocket,客户端使用uniapp 请问服务端和客户端群组互发消息的代码怎么写 2023/8/29 19:22:25 在服务器端使用Django WebSocket和客户端使用Uniapp的情况下,以下是代码示例来实现服务器端和客户端之间的群组互发消息。 服务器端代码 (使用Django Chann

    2024年02月11日
    浏览(46)
  • 使用Go语言的HTTP客户端和服务器

    使用Go语言进行HTTP客户端和服务器开发是一种高效且强大的方式。Go语言的标准库提供了对HTTP协议的全面支持,使得创建HTTP客户端和服务器变得简单。 首先,让我们来看一下如何创建一个简单的HTTP服务器。在Go中,可以使用 net/http 包来创建HTTP服务器。以下是一个简单的示例

    2024年01月16日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包