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

SvelteKit刷新页面报错:SSR中无法提前调用带相对URL的fetch

问题分析与解决

错误原因

这个错误是SvelteKit服务端渲染(SSR)的限制导致的:

  • 服务端渲染时,代码在服务器环境执行,相对URL(比如/api/clients/getClients)没有完整的域名/协议上下文,无法直接发起fetch请求。
  • 刷新页面会触发完整的SSR流程;而正常页面导航是客户端路由,代码只在浏览器环境执行,所以不会触发错误。
  • 你的代码里,$: onChange(client_type, search)是反应式语句,组件初始化(包括SSR阶段)就会执行,里面调用的fetchData直接用了相对URL的fetch,这就触发了服务端的错误。

修复方案

方法1:限制fetch仅在浏览器环境执行

引入SvelteKit的browser变量,判断当前环境是浏览器时才调用请求:

先添加导入:

import { browser } from '$app/environment';

然后修改onChange函数:

function onChange(client_type:string, search:string) {
    data = [];
    newBatch= [];
    offset = 0;
    noMore = false;
    // 仅在浏览器环境发起请求
    if (browser) {
        fetchData();
    }
}

初始的onMount已经是客户端执行,不需要修改。

方法2:使用页面load函数获取初始数据(更符合SvelteKit最佳实践)

如果是页面组件,推荐把初始数据获取放在+page.server.ts或+page.ts的load函数里,服务端可以直接处理API请求,还能把数据传给组件:

比如创建+page.server.ts:

import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ params }) => {
    const client_type = params.type;
    const limit = 30;
    const offset = 0;
    const search = "";

    // 服务端环境下可直接调用API逻辑,或用fetch(SvelteKit会处理相对URL)
    const response = await fetch(`http://你的域名/api/clients/getClients`, {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({ client_type, limit, offset, search })
    });
    const result = await response.json();

    return {
        initialHeaders: result.headers,
        initialData: result.content
    };
};

然后在组件里接收数据:

import type { PageData } from './$types';

export let data: PageData;

// 初始化时直接用load传来的数据
$: headers = data.initialHeaders;
$: data = [...data.initialData];

这种方式适合SSR场景,能实现服务端预渲染数据,提升首屏性能。

额外优化点

  • 你的$: data = [...data, ...newBatch]会在newBatch变化时重复合并,可能导致数据重复,建议在fetchData里直接更新data:
    async function fetchData() {
        const response = await fetch('/api/clients/getClients', {
            // ... 现有代码
        });
        let result = await response.json(); 
        headers = result.headers;
        // 直接追加新数据,避免反应式语句的重复合并
        data = [...data, ...result.content];
        noMore = result.content.length < limit;
    };
    
  • 滚动逻辑里的h = h*2不太合理,建议计算页面总高度和滚动位置的差值来判断是否加载更多:
    function handleScroll() {
        const documentHeight = document.documentElement.scrollHeight;
        // 距离底部200px时触发加载
        if (y + h >= documentHeight - 200 && !noMore) { 
            offset += limit;
            fetchData();
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 10:45:58