Svelte中如何用Fetch轮询外部API?遇实现困境
解决方案:SvelteKit中实现API轮询并解决CORS问题
核心问题分析
- +page.server.js无法轮询:
load函数仅在页面加载/刷新时执行一次,是一次性的服务器端数据获取逻辑,无法在其中通过setInterval实现持续轮询——函数执行完毕后上下文销毁,定时器不会持续运行。 - 客户端直接请求CORS错误:浏览器的同源策略限制前端直接跨域请求外部API,而服务器端请求不受此限制,因此需要通过本地API代理中转请求。
方案一:手动实现轮询(原生Svelte)
步骤1:创建服务器端代理路由
在src/routes/api/proxy/[uid]/+server.js中创建代理,让服务器端转发请求到外部API:
export async function GET({ params }) { // 服务器端请求外部API,无CORS限制 const response = await fetch(`http://localhost:9595/api/v1/chrysalis/example?uid=${params.uid}`); const site = await response.json(); // 返回处理后的数据给客户端 return new Response(JSON.stringify(site[0]), { headers: { 'Content-Type': 'application/json' } }); }
步骤2:客户端实现轮询并清理定时器
在+page.svelte中,通过onMount启动轮询,同时用onDestroy清理定时器避免内存泄漏:
<script> import { onMount, onDestroy } from 'svelte'; export let data; // 接收+page.server.js返回的初始数据 // 用本地变量存储实时更新的数据 let siteData = data; let intervalId; async function fetchLatestData() { // 请求本地代理路由,而非外部API const response = await fetch(`/api/proxy/${data.uid}`); siteData = await response.json(); } onMount(() => { // 每隔3秒执行一次轮询(可根据需求调整间隔) intervalId = setInterval(fetchLatestData, 3000); }); // 页面销毁时清除定时器 onDestroy(() => { if (intervalId) clearInterval(intervalId); }); </script> <!-- 用siteData渲染页面内容 --> <div> <h2>UID: {siteData.uid}</h2> <p>分区数: {siteData.partitions}</p> <!-- 其他数据渲染逻辑 --> </div>
方案二:用Svelte Query实现类SWR的自动轮询
如果习惯Next.js中SWR的用法,可以使用TanStack Svelte Query(原React Query的Svelte版本),它内置了轮询、缓存、错误处理等功能:
步骤1:安装依赖
npm install @tanstack/svelte-query
步骤2:全局配置QueryClient
在src/routes/+layout.svelte中添加全局Provider:
<script> import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query'; const queryClient = new QueryClient(); </script> <QueryClientProvider client={queryClient}> <slot /> </QueryClientProvider>
步骤3:在页面中使用useQuery实现轮询
<script> import { useQuery } from '@tanstack/svelte-query'; export let data; // 配置查询规则,自动轮询 const { data: siteData } = useQuery({ queryKey: ['site-data', data.uid], // 唯一标识查询,用于缓存 queryFn: async () => { const response = await fetch(`/api/proxy/${data.uid}`); return response.json(); }, refetchInterval: 3000, // 轮询间隔(毫秒) initialData: data // 用+page.server.js的初始数据作为首屏内容 }); </script> <!-- 注意用$前缀访问Svelte Query的响应式数据 --> <div> <h2>UID: {$siteData.uid}</h2> <p>分区状态: {$siteData.zStates}</p> </div>
关键说明
- 始终通过服务器端代理访问外部API:彻底规避浏览器CORS限制,同时可在代理层添加请求缓存、鉴权等逻辑。
- 清理定时器:手动实现轮询时必须在页面销毁时清除定时器,防止内存泄漏。
- Svelte Query的优势:无需手动管理定时器,自带缓存、重试、加载状态管理,适合复杂场景。
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

