如何在+page.ts中兼顾SSR与CSR从Cookie获取认证令牌?
要在同时支持SSR和CSR的load函数中,在服务端环境获取Cookie中的access/refresh tokens,且不强制使用SSR(无需依赖+page.server.ts),可以按以下方式实现:
1. 编写环境适配的Cookie解析函数
创建一个能同时在服务端和客户端运行的函数,根据当前环境从对应位置读取并解析Cookie:
import { isServer } from '$app/environment'; /** * 从Cookie中提取access和refresh令牌 * @param request 服务端环境下传入的Request对象 */ function extractTokens(request?: Request) { let cookieString = ''; if (isServer) { if (!request) throw new Error('Request must be provided in server context'); cookieString = request.headers.get('cookie') || ''; } else { cookieString = document.cookie; } // 解析Cookie字符串为键值对 const cookiePairs = cookieString.split(';').map(pair => pair.trim()); const cookies: Record<string, string> = {}; for (const pair of cookiePairs) { const [key, value] = pair.split('=', 2); if (key && value) { cookies[key] = decodeURIComponent(value); } } return { accessToken: cookies.access_token, refreshToken: cookies.refresh_token }; }
2. 修改load函数逻辑
在load函数中,根据当前环境传入对应的参数调用解析函数,并基于令牌完成身份校验和数据请求:
import type { PageLoad } from './$types'; import { isServer, browser } from '$app/environment'; import { goto, redirect } from '$app/navigation'; export const load: PageLoad = async (obj) => { // 提取令牌:服务端传入request,客户端无需参数 const { accessToken, refreshToken } = extractTokens(isServer ? obj.request : undefined); // 调整身份校验函数,传入令牌进行验证 if (await ifAuthenticated(accessToken, refreshToken)) { // 请求第三方服务时携带令牌 const response = await fetch('https://third-party-service.com/api/data', { headers: { Authorization: `Bearer ${accessToken}` } }); if (!response.ok) { // 处理请求失败逻辑,比如令牌过期时刷新令牌 throw new Error('Failed to fetch data'); } return await response.json(); } else { // 未认证时跳转登录页,区分服务端和客户端逻辑 if (browser) { goto('/login'); } else { throw redirect(307, '/login'); } } };
核心要点
- 保持
load函数的通用性:不使用+page.server.ts,这样客户端导航(比如点击路由链接)时会走CSR,只有首次访问或页面刷新时触发SSR。 - 服务端环境必须通过
request.headers获取Cookie:服务端没有document对象,直接读取会导致运行时错误。 - 令牌安全:确保Cookie配置了
HttpOnly、Secure和SameSite属性,防止XSS和CSRF攻击。
内容的提问来源于stack exchange,提问作者Don Tomato
相关产品推荐
相关产品推荐

