Supabase开启RLS后查询返回406 JSON object requested错误
Supabase开启RLS后查询返回406错误解决方案
问题现象
- 已查阅StackOverflow、Supabase相关GitHub仓库(supabase/postgrest-js、PostgREST/postgrest)的issue,也检索了Discord社区相关讨论,现有公开方案均未生效。
- RLS(行级安全)关闭时代码运行完全符合预期,开启RLS后查询返回406错误。
测试代码
export const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY) const { data, error } = await supabase.from('profiles').select('*').eq('id', userId).maybeSingle() // 以下两种写法在RLS关闭时均可正常运行 // const { data, error } = await supabase.from('profiles').select('*').eq('id', userId).limit(1).single() // const { data, error } = await supabase.from('profiles').select('*').eq('id', userId).single()
响应对比
RLS关闭时正常返回数据:
{ "id": "123-123-1241-1231", "created_at": "2022-06-10T03:59:22.751125+00:00", "is_subscribed": false, "interval": null, "email": "test@example.com" }
RLS开启后返回错误:
{ "message": "请求JSON对象格式响应,但返回了多行(或零行)结果", "details": "结果包含0行数据,application/vnd.pgrst.object+json类型要求必须返回1行数据" }
已尝试操作
- 重载schema、重新编写安全策略,问题未解决
profiles表id字段关联auth.users.id,最初安全策略针对anon角色配置,后尝试将目标角色改为authenticated,策略规则为:(uid() = id)- 尝试将原表名
profile改为复数形式profiles,问题依然存在
根因分析
这个错误和查询写法、表名、schema缓存无关,RLS关闭时查询正常已经证明语法完全正确,核心原因是RLS策略拦截了查询,当前请求身份没有权限读取目标行,数据库实际返回了0行结果。
按以下优先级排查修复即可:
- 检查请求携带的身份凭证是否有效
策略规则(uid() = id)生效的前提是uid()能正确获取到当前登录用户ID:- 客户端侧请求:必须先完成Supabase登录流程(邮箱密码、第三方OAuth等),未登录状态下请求走匿名身份,
uid()返回null,永远无法匹配到对应ID的行 - Next.js服务端组件/路由处理程序中发起请求:仅用公网可获取的anon key初始化客户端拿不到用户登录态,必须从请求Cookie/头信息中提取当前用户的认证token注入Supabase客户端,否则服务端请求默认使用匿名身份,会被RLS直接拦截
- 客户端侧请求:必须先完成Supabase登录流程(邮箱密码、第三方OAuth等),未登录状态下请求走匿名身份,
- 检查RLS策略配置正确性
进入Supabase后台策略编辑页逐项确认:- 为
profiles表的SELECT操作单独配置策略,不要和INSERT/UPDATE等操作共用策略导致漏选SELECT权限 - 策略生效角色仅勾选
authenticated即可,不要给anon(未登录匿名用户)角色配置用户私有表的访问权限,避免数据泄露 - 策略规则直接使用
id = auth.uid()即可,无需额外加其他过滤条件
- 为
- 验证策略实际执行效果
打开Supabase内置SQL编辑器,执行以下语句模拟认证用户查询,直接在数据库层验证策略是否生效:
如果上述语句依然返回空结果,检查表结构配置:-- 替换为你实际测试的用户UUID SET request.jwt.claim.sub = '123-123-1241-1231'; SET ROLE authenticated; -- 执行查询看是否能返回目标数据 SELECT * FROM profiles WHERE id = '123-123-1241-1231';- 确认
profiles.id字段类型为uuid,和auth.users.id字段类型完全一致,类型不匹配会导致等值判断失效 - 确认
profiles表中确实存在对应用户ID的记录,没有因为注册触发器未生效、手动操作等原因缺失用户profile行
- 确认
内容的提问来源于stack exchange,提问作者Scott Yu
相关产品推荐
相关产品推荐

