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

如何在SvelteKit服务端与客户端每次请求中刷新并携带Auth令牌

问题关联说明

你遇到的问题和该SvelteKit issue的核心逻辑完全一致:SSR场景下服务端执行load函数时,使用的是SvelteKit内部封装的服务端fetch实例,和客户端运行时的全局fetch不属于同一上下文,仅针对客户端全局fetch做的拦截逻辑在服务端不会生效,所以会出现Auth头丢失的问题。


可行解决方案

你需要分别覆盖客户端、服务端两个运行环境的fetch逻辑,不要仅修改单一位置:

1. 抽离通用签名生成工具

先把HMAC签名逻辑抽成跨端通用工具,appID和appSecret存在.env文件中,两端分别用对应环境变量读取即可:

// src/lib/utils/hmac.js
import crypto from 'crypto'
// 客户端如果不支持node crypto,可以替换为crypto-js,保持算法一致即可

export function genAuthHeader(method, path, body = null) {
  const appId = import.meta.env.VITE_APP_ID
  const appSecret = import.meta.env.VITE_APP_SECRET
  const timestamp = Math.floor(Date.now() / 1000)
  const signContent = `${method}${path}${timestamp}${body ? JSON.stringify(body) : ''}`
  const signature = crypto.createHmac('sha256', appSecret).update(signContent).digest('hex')
  return `${appId}:${timestamp}:${signature}`
}

2. 配置客户端fetch拦截

在客户端入口给全局fetch加拦截,所有客户端发起的请求自动携带Auth头:

// src/routes/+layout.client.js
import { genAuthHeader } from '$lib/utils/hmac'

const originalFetch = window.fetch
window.fetch = async (input, init = {}) => {
  const url = new URL(input, window.location.origin)
  init.headers = {
    ...init.headers,
    Auth: genAuthHeader(init.method || 'GET', url.pathname, init.body)
  }
  return originalFetch(input, init)
}

3. 配置服务端fetch拦截

在服务端hooks中重写event.fetch,给所有服务端load函数发起的请求加头:

// src/hooks.server.js
import { genAuthHeader } from '$lib/utils/hmac'

export async function handle({ event, resolve }) {
  const originalFetch = event.fetch
  // 重写load函数注入的fetch实例
  event.fetch = async (input, init = {}) => {
    const url = new URL(input)
    init.headers = {
      ...init.headers,
      Auth: genAuthHeader(init.method || 'GET', url.pathname, init.body)
    }
    return originalFetch(input, init)
  }
  return resolve(event)
}

4. 适配现有统一请求模块

你现有的api.js模块不需要做大量修改,只需要注意在load函数中调用请求方法时,把load自带的fetch参数传入即可:

// api.js示例方法
export async function getBlogList(fetchInstance) {
  const res = await (fetchInstance || window.fetch)('/your/backend/api/blog')
  return res.json()
}

// load函数中调用示例
export async function load({ fetch }) {
  // 必须传入load自带的fetch实例
  const blogList = await getBlogList(fetch)
  return { blogList }
}

之前修改不生效的原因

你之前在api.js中加的逻辑如果是直接绑定全局fetch,服务端运行时不会触发该逻辑;如果在handle钩子中修改的是返回给客户端的响应头、或者客户端请求的入站头,也不会影响load函数内部发起的对外请求,按上述步骤调整即可覆盖两端所有请求场景。

内容的提问来源于stack exchange,提问作者Subhendu Pratap Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 13:30:00