页面重载后首次调用TRPC useQuery出现Null session问题排查
问题:页面重载时TRPC上下文里的NextAuth Session为null
我正在使用Next.js、TRPC、NextAuth(Prisma组件无问题)开发应用,有一个展示元素集合的页面,通过经过身份验证的TRPC useQuery获取集合数据:
function Collection() { const { data: session } = useSession(); const collectionsQuery = trpc.collectionRouter.collection.useQuery(); if (session) { return ( <div> <Layout> <h1>Collections</h1> <Link href="/collections/add" className="btn btn-sm btn-success mb-2">Add Collection</Link> <div> { collectionsQuery.data && collectionsQuery.data.length != 0 ? JSON.stringify(collectionsQuery.data) : <div className="p-2">No collections To Display</div> } </div> </Layout> </div> ); } else { return ( <div>Not logged</div> ) } }
页面重载时该查询总是失败,但通过应用菜单导航到其他页面再返回后,所有查询均可成功执行。在服务端context.ts中,页面重载时getSession返回null,后续所有调用均正常:
export async function createContext(opts: trpcNext.CreateNextContextOptions) { const session = await getSession(opts); if (session == null) { console.log("null session"); } return { session, }; };
补充信息
- 编辑1:页面重载查询失效时,客户端已正确设置auth cookie,但服务端无法获取该cookie。
- 编辑2:尝试过相关解决方案,在
createTRPCNext/config中添加请求头转发代码,但无效,甚至该代码未被调用:
headers: () => { if (ctx?.req) { // on ssr, forward client's headers to the server return { ...ctx.req.headers, 'x-ssr': '1', }; } }
解决思路及方案
1. 检查NextAuth Cookie配置
确认NextAuth的session配置中,cookie参数适配运行环境:
- 本地开发用
http时,secure设为false,否则浏览器不会在非HTTPS环境下发cookie到服务端; - 生产HTTPS环境下,
secure设为true,同时sameSite设为'lax'或'strict'避免跨域问题; - 检查
cookie.path是否与应用根路径匹配,默认是/,子路径部署时需调整。
示例配置:
// [...nextauth].ts export default NextAuth({ session: { strategy: 'jwt', cookie: { secure: process.env.NODE_ENV === 'production', sameSite: 'lax', path: '/', maxAge: 24 * 60 * 60, // 1天有效期 }, }, // 其他配置... });
2. 修复TRPC客户端的请求头转发
确保TRPC客户端在SSR时完整转发请求头,完整配置示例:
// trpc/client.ts export const trpc = createTRPCNext<AppRouter>({ config({ ctx }) { return { headers() { // SSR环境下转发客户端请求头(含cookie)到TRPC服务端 if (ctx?.req) { return { ...ctx.req.headers, 'x-trpc-source': 'ssr', }; } return {}; }, }; }, ssr: false, // 禁用SSS缓存避免 stale 数据问题 });
同时确认createContext正确传递请求对象给getSession:
// trpc/context.ts export async function createContext(opts: trpcNext.CreateNextContextOptions) { // 明确传递req和res给getSession const session = await getSession({ req: opts.req, res: opts.res }); return { session }; }
3. 调整页面渲染模式
如果页面用静态生成(SSG),getSession在构建阶段无法获取用户会话,导致SSR时session为null,可通过以下方式修改:
- 启用服务器端渲染(SSR):在页面组件添加
getServerSideProps:
// pages/collections.tsx export const getServerSideProps = async () => { return { props: {} }; }; function Collection() { // 组件内容... }
- 禁用SSR强制客户端渲染:用Next.js的
dynamic组件:
// pages/collections.tsx import dynamic from 'next/dynamic'; const Collection = dynamic(() => import('./CollectionComponent'), { ssr: false }); export default Collection;
4. 控制TRPC查询触发时机
避免在session未就绪时触发查询,利用useSession的status状态控制查询启用时机:
function Collection() { const { data: session, status } = useSession(); // 仅会话验证通过后才触发查询 const collectionsQuery = trpc.collectionRouter.collection.useQuery(undefined, { enabled: status === 'authenticated', }); if (status === 'loading') { return <div>Loading...</div>; } if (!session) { return <div>Not logged</div>; } return ( // 页面内容... ); }
内容的提问来源于stack exchange,提问作者PeO
相关产品推荐
相关产品推荐

