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

为何Sveltekit的handleFetch仅在全页重载时能正常拦截请求?

问题原因

你踩了SvelteKit handleFetch 的一个常见坑:这个钩子只在服务器端生效,完全管不到浏览器端发起的请求。

  • 全页刷新(F5、直接输URL)时,页面是SSR渲染,page.ts 里的 fetch 是在服务器端触发的,所以 handleFetch 能拦截并加上 Authorization 头,请求正常。
  • 用 a href、redirect 这类客户端导航时,页面是在浏览器端渲染的,page.ts 里的 fetch 是浏览器直接发的,这时候 hooks.server.ts 里的 handleFetch 根本不会运行,自然没加请求头,导致接口报错。

你看到的控制台日志是服务器端的输出,对应的可能是之前全页刷新的请求,不是客户端导航时的那个请求。

解决方案

需要同时处理服务器端和客户端的 fetch 请求,下面给两种可行方案:

方案一:封装全局自定义 fetch 函数

创建一个通用的 fetch 封装,自动在客户端和服务器端添加请求头:

  1. 在 src/lib 下新建 fetch.ts:
import { browser } from '$app/environment';

export async function customFetch(url: string, options: RequestInit = {}) {
    const headers = new Headers(options.headers);

    // 只给目标域名的请求加Authorization头
    if (url.startsWith('http://')) {
        let accessToken;
        if (browser) {
            // 客户端从document.cookie中取token
            accessToken = document.cookie.split('; ')
                .find(row => row.startsWith('access_token='))?.split('=')[1];
        }
        // 服务器端的请求已经由handleFetch处理,这里不用重复操作

        if (accessToken) {
            headers.set('Authorization', `Bearer ${accessToken}`);
        }
    }

    return fetch(url, {
        ...options,
        headers
    });
}
  1. 在 page.ts 里替换成这个自定义函数:
import type { PageLoad } from './$types';
import { customFetch } from '$lib/fetch';

export const load: PageLoad = async () => {
    const response = await customFetch('http://127.0.0.1:8080/api/v1/fetch_accounts', {
        method: 'GET',
        credentials: 'include'
    });

    const content = await response.json();
    return { content };
};

方案二:用客户端钩子拦截 fetch

创建 hooks.client.ts,专门处理浏览器端的 fetch 请求:

export async function handleFetch({ request, fetch }) {
    if (request.url.startsWith('http://')) {
        // 从客户端cookie中取token
        const accessToken = document.cookie.split('; ')
            .find(row => row.startsWith('access_token='))?.split('=')[1];
        
        if (accessToken) {
            request.headers.set('Authorization', `Bearer ${accessToken}`);
        }
    }
    return fetch(request);
}

这个钩子会拦截所有浏览器端发起的 fetch 请求,自动加上请求头,不需要修改 page.ts 里的代码。

额外注意点
  • 确保你的 access_token cookie没有设置 HttpOnly 属性(如果要在客户端读取的话),如果是HttpOnly,客户端拿不到,只能依赖服务器端的 handleFetch 处理SSR请求,同时后端要配置允许cookie自动携带。
  • 服务器端的 handleFetch 逻辑可以保留,继续处理SSR时的请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:02:49