如何在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
相关产品推荐
相关产品推荐

