寻求实时获取外部JSON数据方案:替代定时轮询实现通知应用
Hey there! Let's tackle this real-time JSON data fetching problem you're facing—those fixed-interval timeouts can be such a pain for a notification app, right? Either you're hitting the API too often (wasting resources) or missing updates because the interval's too long. Here are some practical, actionable solutions to try:
1. Server-Sent Events (SSE) – Simple One-Way Push
If you only need to receive updates (not send data back to the external source), SSE is way simpler than WebSockets. The catch? You'll need a small middleman server (since most external JSON APIs don't support SSE natively) that polls the external JSON, checks for changes, and pushes updates to your frontend via SSE.
Frontend Example (Browser JS):
const eventSource = new EventSource('/api/json-updates'); eventSource.onmessage = (event) => { const updatedData = JSON.parse(event.data); // Trigger your notification logic here showNotification(updatedData); }; eventSource.onerror = (error) => { console.error('SSE connection error:', error); eventSource.close(); // Optionally retry connection after a delay };
Node.js Middleman Server Example:
const express = require('express'); const app = express(); const fetch = require('node-fetch'); let lastData = null; // Endpoint for SSE app.get('/api/json-updates', (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); // Initial check checkForUpdates(res); // Poll external JSON every 30 seconds (adjust as needed) const interval = setInterval(() => checkForUpdates(res), 30000); req.on('close', () => { clearInterval(interval); res.end(); }); }); async function checkForUpdates(res) { try { const response = await fetch('https://external-api.com/data.json'); const currentData = await response.json(); if (JSON.stringify(currentData) !== JSON.stringify(lastData)) { lastData = currentData; // Send update to client res.write(`data: ${JSON.stringify(currentData)}\n\n`); } } catch (err) { console.error('Error fetching external JSON:', err); } } app.listen(3000, () => console.log('SSE server running on port 3000'));
2. Smart Polling with Dynamic Intervals
If you can't set up a middleman server, optimize your existing polling to avoid fixed intervals. Adjust the delay based on whether the data changed:
- If data updates frequently, use a shorter interval
- If no changes for a while, gradually increase the interval (to reduce API calls)
Example Code:
let pollInterval = 10000; // Start with 10 seconds let lastData = null; function pollForUpdates() { fetch('https://external-api.com/data.json') .then(res => res.json()) .then(currentData => { if (JSON.stringify(currentData) !== JSON.stringify(lastData)) { lastData = currentData; showNotification(currentData); pollInterval = 10000; // Reset to short interval after update } else { // Increase interval by 5 seconds, cap at 60 seconds pollInterval = Math.min(pollInterval + 5000, 60000); } setTimeout(pollForUpdates, pollInterval); }) .catch(err => { console.error('Polling error:', err); setTimeout(pollForUpdates, pollInterval); // Retry even on error }); } // Start polling pollForUpdates();
3. WebSockets with Middleman (For Two-Way or Low-Latency Needs)
You mentioned trying WebSockets without luck—chances are the external JSON API doesn't support WebSocket connections directly. The fix is to build a Node.js middleman that:
- Polls the external JSON API
- Detects changes
- Pushes updates to connected frontend clients via WebSockets
Node.js WebSocket Server Example (using ws library):
const WebSocket = require('ws'); const fetch = require('node-fetch'); const wss = new WebSocket.Server({ port: 8080 }); let lastData = null; // Poll external JSON every 20 seconds setInterval(async () => { try { const response = await fetch('https://external-api.com/data.json'); const currentData = await response.json(); if (JSON.stringify(currentData) !== JSON.stringify(lastData)) { lastData = currentData; // Send update to all connected clients wss.clients.forEach(client => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify(currentData)); } }); } } catch (err) { console.error('Error fetching external JSON:', err); } }, 20000); // Handle new client connections wss.on('connection', (ws) => { console.log('New client connected'); // Send initial data to new clients if (lastData) { ws.send(JSON.stringify(lastData)); } ws.on('close', () => { console.log('Client disconnected'); }); });
Frontend WebSocket Client:
const socket = new WebSocket('ws://localhost:8080'); socket.onopen = () => { console.log('WebSocket connection established'); }; socket.onmessage = (event) => { const updatedData = JSON.parse(event.data); showNotification(updatedData); }; socket.onerror = (error) => { console.error('WebSocket error:', error); }; socket.onclose = () => { console.log('WebSocket connection closed'); // Optionally reconnect after a delay setTimeout(() => window.location.reload(), 5000); };
Pro Tips to Optimize
- Use HTTP Headers: Check the
ETagorLast-Modifiedheaders from the external API to avoid downloading the entire JSON every time. Only fetch the full data if the ETag has changed. - CORS Handling: If the external API doesn't allow cross-origin requests, your middleman server will handle this by proxying the request.
- Rate Limiting: Make sure your polling interval respects the external API's rate limits to avoid getting blocked.
内容的提问来源于stack exchange,提问作者Dion Grendelman

