You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Express JS后端高效获取体育API实时比分更新?

高效集成体育API到Express后端的实时比分方案

核心思路

因为体育API不支持主动推送事件,直接轮询会浪费资源,采用**后端智能轮询+前端SSE(Server-Sent Events)**的组合:

  • 后端只在API返回的比分数据发生变化时,才主动推送给所有连接的前端
  • 前端通过SSE保持与后端的长连接,实时接收更新,避免频繁发起请求

具体实现步骤

后端侧(Express)

  1. 缓存与数据对比

    • 用缓存工具(如node-cache)存储最新的比分数据,通过内容对比或哈希值判断数据是否更新,避免重复推送
    • 定时调用体育API,仅当返回数据与缓存不一致时,更新缓存并推送给前端
  2. SSE接口实现

    • 搭建SSE接口,维护活跃的前端连接列表,数据变化时批量推送
    • 处理连接断开的清理逻辑,避免无效连接占用资源
  3. 代码示例:

const express = require('express');
const NodeCache = require('node-cache');
const axios = require('axios');
const crypto = require('crypto');

const app = express();
app.use(express.json());
const scoreCache = new NodeCache({ stdTTL: 3600 });
const SPORTS_API_URL = '你的体育API地址';
let pollInterval = 30000; // 初始30秒轮询,可动态调整

// 维护SSE连接的Map
const sseClients = new Map();

// SSE接口
app.get('/api/score-stream', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  res.setHeader('Access-Control-Allow-Origin', '*'); // 跨域场景需配置

  // 首次连接发送当前缓存数据
  const currentScores = scoreCache.get('latestScores');
  if (currentScores) {
    res.write(`data: ${JSON.stringify(currentScores)}\n\n`);
  }

  const clientId = Date.now();
  sseClients.set(clientId, res);

  // 连接断开时清理
  req.on('close', () => {
    sseClients.delete(clientId);
  });
});

// 生成数据哈希值,用于对比更新
const generateDataHash = (data) => {
  return crypto.createHash('md5').update(JSON.stringify(data)).digest('hex');
};

// 智能轮询任务
const pollSportsAPI = async () => {
  try {
    const response = await axios.get(SPORTS_API_URL);
    const newScores = response.data;
    const cachedData = scoreCache.get('scoreData');

    const newHash = generateDataHash(newScores);
    // 对比哈希值判断是否更新
    if (!cachedData || cachedData.hash !== newHash) {
      scoreCache.set('scoreData', { hash: newHash, data: newScores });
      scoreCache.set('latestScores', newScores);
      // 推送给所有活跃客户端
      sseClients.forEach((res) => {
        res.write(`data: ${JSON.stringify(newScores)}\n\n`);
      });
    }
  } catch (err) {
    console.error('API请求失败:', err.message);
  }
};

// 启动轮询
setInterval(pollSportsAPI, pollInterval);

// 动态调整轮询间隔(比如根据赛事状态)
app.post('/api/update-poll-interval', (req, res) => {
  const { interval } = req.body;
  if (interval && interval > 1000) {
    pollInterval = interval;
    res.send({ success: true });
  } else {
    res.status(400).send({ success: false, msg: '无效的间隔值(需大于1秒)' });
  }
});

app.listen(3000, () => console.log('Express服务启动于端口3000'));

前端侧

  1. SSE连接与更新

    • 使用EventSource连接后端SSE接口,监听消息事件更新UI
    • 处理连接异常的重连逻辑
  2. 代码示例:

// 初始化SSE连接
function initScoreStream() {
  const eventSource = new EventSource('/api/score-stream');

  eventSource.onmessage = (event) => {
    const scores = JSON.parse(event.data);
    renderScoreBoard(scores);
  };

  eventSource.onerror = () => {
    console.warn('SSE连接断开,3秒后重试');
    eventSource.close();
    setTimeout(initScoreStream, 3000);
  };
}

// 渲染比分板
function renderScoreBoard(scores) {
  const container = document.getElementById('score-board');
  container.innerHTML = scores.map(match => `
    <div class="match-card">
      <div class="team">${match.homeTeam}</div>
      <div class="score">${match.homeScore} - ${match.awayScore}</div>
      <div class="team">${match.awayTeam}</div>
      <div class="status">${match.status}</div>
    </div>
  `).join('');
}

// 页面加载时启动
window.addEventListener('load', initScoreStream);

优化建议

  • 动态轮询间隔:根据赛事状态调整,比如赛事进行中缩短至10-15秒,休赛期延长至5-10分钟
  • API请求优化:批量请求多场赛事数据,减少单次请求数量;严格遵守API的限流规则,避免被封禁
  • 缓存策略优化:用哈希值对比数据比直接字符串对比更高效,减少计算开销
  • 连接管理:后端定期清理长时间无响应的SSE连接,降低内存占用

内容的提问来源于stack exchange,提问作者seun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:25:37