React/Next.js客户端组件向服务端组件传递token的方案咨询
我并非React/Next.js开发人员,当前需要将客户端组件Vendas中的token参数传递给服务端组件Home,遇到以下问题:
- 尝试通过Cookie实现传递,但在Chrome浏览器的iframe环境下失效——已设置Cookie的
sameSite: none及secure属性,服务端组件Home仍无法读取到该Cookie。 - 曾尝试使用localStorage,但由于Home是服务端组件,该方式无法生效;
- 也曾尝试通过路由query传参,但操作方式有误,且不清楚如何在Home组件中接收参数。
Vendas组件(客户端组件)
"use client"; import { useRouter } from "next/navigation"; import { jwtDecode } from "jwt-decode"; import { useEffect } from "react"; import Lottie from "lottie-react"; import animationData from "@/animations/spinner.json"; import { setCookie } from "nookies"; interface TokenProps { PROFILE: string; WORKPLACE_ID: string; sub: string; exp: number; } export default function Vendas({ searchParams, }: { searchParams: { [key: string]: string | string[] | undefined }; }) { const token = searchParams.token; const router = useRouter(); useEffect(() => { if (token != undefined && typeof token === "string") { const decoded = jwtDecode<TokenProps>(token); setCookie(undefined, "token", token, { maxAge: 60 * 60 * 1, sameSite: "none", secure: true, }); if (decoded.PROFILE === "GENERAL") { router.push(`/vendas-varejo/geral`); } else if (decoded.PROFILE === "SELLER") { router.push(`/vendas-varejo/vendedor`); } else { router.push(`/vendas-varejo/loja`); } } else { throw new Error("Token de acesso não encontrado"); } }); return ( <div className="flex h-screen items-center justify-center bg-blue-700"> <div className="flex h-[70%]"> <Lottie animationData={animationData} /> </div> </div> ); }
Home组件(服务端组件)
import { GeneralProps } from "@/@types/vendas-varejo/general"; import { fetcher } from "@/utils/api"; import Body from "./components/Body"; import { jwtDecode } from "jwt-decode"; import { cookies } from "next/headers"; interface TokenProps { PROFILE: string; WORKPLACE_ID: string; sub: string; exp: number; } export default async function Home() { const cookieStore = cookies(); const token = cookieStore.get("token"); if (token?.value != undefined && typeof token === "string") { const decoded = jwtDecode<TokenProps>(token); if (decoded.PROFILE != "GENERAL") { throw new Error("Você não tem permissão para acessar esta página"); } } async function getData() { const data = await fetcher("/retail-sales", { token: token?.value, }); return data; } const data: GeneralProps = await getData(); return ( <> <h1 className="mx-3 mt-2"> Última Atualização: {data.lastUpdate} </h1> <div> <Body data={data} token={token?.value} /> </div> </> ); }
可行解决方案
1. 修复iframe环境下的Cookie读取问题
iframe环境下Cookie无法读取,除了已设置的sameSite: none和secure,还需确认以下几点:
- 网站必须运行在HTTPS协议下(
secure属性要求Cookie只能在HTTPS环境中传输,本地开发可启用Next.js的HTTPS模式); - 检查Cookie的
domain设置:如果iframe嵌入的是不同域名,需确保domain设置正确,或不指定domain让浏览器自动处理; - 查看Chrome隐私设置:Chrome默认会在部分场景下阻止第三方Cookie,需确保你的站点在用户的允许列表中,或引导用户开启第三方Cookie权限。
2. 路由Query参数传递(修正操作方式)
这种方式适合快速验证,但token会暴露在URL中,存在安全风险,仅建议短期测试或非敏感场景使用。
客户端组件Vendas中传递参数
修改router.push逻辑,将token编码后作为query参数携带:
// 在Vendas组件的useEffect中修改跳转代码 if (decoded.PROFILE === "GENERAL") { router.push(`/vendas-varejo/geral?token=${encodeURIComponent(token)}`); } else if (decoded.PROFILE === "SELLER") { router.push(`/vendas-varejo/vendedor?token=${encodeURIComponent(token)}`); } else { router.push(`/vendas-varejo/loja?token=${encodeURIComponent(token)}`); }
使用encodeURIComponent编码token,避免特殊字符导致的路由解析错误。
服务端组件Home中接收参数
服务端组件可通过searchParams参数直接获取路由query:
// 修改Home组件的定义,接收searchParams参数 export default async function Home({ searchParams, }: { searchParams: { [key: string]: string | string[] | undefined }; }) { const token = searchParams.token as string | undefined; // 验证token逻辑 if (token) { const decoded = jwtDecode<TokenProps>(token); if (decoded.PROFILE !== "GENERAL") { throw new Error("Você não tem permissão para acessar esta página"); } } async function getData() { return await fetcher("/retail-sales", { token }); } const data: GeneralProps = await getData(); return ( <> <h1 className="mx-3 mt-2"> Última Atualização: {data.lastUpdate} </h1> <div> <Body data={data} token={token} /> </div> </> ); }
3. 客户端中转+Server Action(更安全)
如果不想用Cookie或暴露token在URL中,可通过Server Action实现安全传递:
- 在服务端创建一个Server Action,接收token并返回所需数据;
- 在客户端组件中调用该Action,传入token;
- 服务端组件改为客户端组件,或通过客户端组件渲染数据。
这种方式避免了token暴露,且适配iframe环境,但需要调整组件结构。
内容的提问来源于stack exchange,提问作者Victor Lindberg
相关产品推荐
相关产品推荐

