Next.js13部署Vercel出现客户端异常的原因及解决方法
问题原因与解决方案
核心原因
- Supabase客户端跨环境复用问题:SSR过程中,服务端创建的Supabase实例被意外传递到客户端,服务端渲染完成后连接被关闭,客户端后续异步操作尝试使用已关闭的连接,触发错误。
- React-Query SSR数据hydration不完整:服务端预取数据时,异步查询未完全完成就返回页面,导致客户端接收的缓存数据不匹配,后续异步响应时消息通道已关闭。
- 实时订阅误用:在服务端组件中初始化Supabase实时订阅,服务端渲染结束后订阅连接被销毁,客户端接管时触发连接关闭错误。
解决步骤
1. 严格分离Supabase服务端/客户端实例
确保服务端和客户端使用各自的Supabase初始化方法,避免跨环境复用实例:
- 服务端组件(App Router):使用
createServerComponentClient,依赖next/headers的cookies:import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'; import { cookies } from 'next/headers'; export default async function SSRPage() { const supabase = createServerComponentClient({ cookies }); // 等待查询完成后再渲染 const { data } = await supabase.from('your_table').select('*'); return <div>{JSON.stringify(data)}</div>; } - 客户端组件:使用
createClientComponentClient,无需传递cookies:import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'; export default function ClientPage() { const supabase = createClientComponentClient(); // 客户端侧的数据操作 return <div>Client Content</div>; }
2. 确保React-Query SSR数据正确传递
使用dehydrate和Hydrate组件完成服务端数据预取与客户端缓存同步,避免异步操作未完成就结束渲染:
import { dehydrate, QueryClient } from '@tanstack/react-query'; import { Hydrate } from '@tanstack/react-query-nextjs'; import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'; import { cookies } from 'next/headers'; import ClientComponent from './ClientComponent'; export default async function SSRPage() { const queryClient = new QueryClient(); // 等待查询完成,确保数据被预取 await queryClient.fetchQuery({ queryKey: ['your_data'], queryFn: async () => { const supabase = createServerComponentClient({ cookies }); const { data } = await supabase.from('your_table').select('*'); return data; }, }); return ( <Hydrate state={dehydrate(queryClient)}> <ClientComponent /> </Hydrate> ); }
注意:客户端组件中使用useQuery时,queryKey要与服务端预取的一致,确保直接复用缓存数据。
3. 避免在服务端组件中使用实时订阅
Supabase实时订阅属于客户端特性,必须放在客户端组件的生命周期钩子中初始化:
// 客户端组件中使用实时订阅 import { useEffect } from 'react'; import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'; export default function ClientComponent() { const supabase = createClientComponentClient(); useEffect(() => { const channel = supabase.channel('your_table') .on('INSERT', (payload) => { console.log('New record:', payload.new); }) .subscribe(); // 组件卸载时取消订阅 return () => { supabase.removeChannel(channel); }; }, [supabase]); return <div>Real-time Content</div>; }
4. 检查Vercel部署配置
- 若使用Edge Runtime,确保
@supabase/auth-helpers-nextjs版本适配(v0.7.0+支持Edge环境); - 在Vercel控制台调整Serverless函数超时时间(默认10秒,可延长至60秒),避免服务端查询未完成就被终止;
- 查看Vercel函数日志,确认是否有服务端报错导致连接提前关闭。
内容的提问来源于stack exchange,提问作者vlovin
相关产品推荐
相关产品推荐

