Flutter调用Supabase Edge函数删用户遇FormatException求助
调用Supabase Edge函数删除用户时触发FormatException异常
调用Supabase Edge函数删除用户时遭遇FormatException,错误信息如下:
FormatException: Unexpected character (at character 1) <!DOCTYPE html>
触发错误的Flutter代码片段
Future<void> handlingUserDeletion() async { try { await supabase.functions.invoke( "delete-user", headers: { 'Authorization': 'Bearer ${supabase.auth.currentSession?.accessToken}' }, ); if (mounted) { supabase.auth.signOut(); } } on PostgrestException catch (error) { debugPrint(error.message); } catch (e) { debugPrint(e.toString()); } }
Supabase Edge函数(delete-user)代码
import { serve } from 'https://deno.land/std@0.182.0/http/server.ts'; import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.14.0'; import { corsHeaders } from '../_shared/cors.ts'; console.log("Delete user account function"); serve(async (request) => { // This is needed if you're planning to invoke your function from a browser. if (request.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }) } try { //Create instance of SupabaseClient const supabaseClient = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '', { global: { headers: { Authorization: request.headers.get('Authorization')! } } } ); // Create a user object which contains the data we need to identify the user.id const { data: { user }, } = await supabaseClient.auth.getUser() // Throw an error if there are any issues with identifying the users from the token if (!user) throw new Error('No user found for JWT!'); // Create supabaseAdmin client which specifically uses the Service Role // Key in order to perform elavated administration actins const supabaseAdmin = createClient( Deno.env.get('SUPABASE_URL') ?? '', Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '' ) // Call the deleteUser method on the supabaseAdmin client and pass the user.id const { data: deletion_data, error: deletion_error } = await supabaseAdmin.auth.admin.deleteUser(user.id, true); // Log deletion error so we can debug. Delete if not required! // console.log(deletion_error); if (deletion_error) throw deletion_error; // Return a response of the user which has been deleted return new Response("User deleted: " + JSON.stringify(deletion_data, null, 2), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 200, }); } catch (error) { // Return an error with the error message should it run in to any issues return new Response(JSON.stringify({ error: error.message }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 400, }) } });
cors.ts文件代码
export const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', }
版本信息
- Flutter 3.10.6
- supabase_flutter: ^1.8.1
异常原因分析
这个FormatException说明Flutter客户端接收到的响应不是合法的JSON格式,而是HTML内容。通常是Edge函数执行出错后,Supabase返回了默认的错误页面(HTML格式),而非函数本身定义的JSON错误响应。可能的触发点包括:
- Edge函数的成功响应格式不合法,返回了非纯JSON内容
- 环境变量未正确配置,导致Supabase客户端初始化失败
- 请求的Authorization令牌为空或无效,导致函数内部抛出未被正确处理的错误
- 函数内部的非空断言触发运行时错误,未进入catch块返回JSON响应
可行解决办法
修正Edge函数的响应格式
成功响应中,不要在JSON前拼接字符串"User deleted: ",因为Content-Type设为application/json,必须返回纯JSON内容。修改成功响应代码:return new Response(JSON.stringify({ message: "User deleted", data: deletion_data }, null, 2), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 200, });检查并确保环境变量正确配置
在Supabase控制台的Edge函数设置中,确认SUPABASE_URL和SUPABASE_SERVICE_ROLE_KEY已正确添加,且值不为空。函数中可以添加空值检查,提前抛出明确错误:const supabaseUrl = Deno.env.get('SUPABASE_URL'); const serviceRoleKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY'); if (!supabaseUrl || !serviceRoleKey) { throw new Error('Missing Supabase environment variables'); }处理Authorization头为空的情况
- Flutter端:调用函数前先检查当前会话是否存在,避免发送空令牌:
final session = supabase.auth.currentSession; if (session == null) { debugPrint('No active session'); return; } await supabase.functions.invoke( "delete-user", headers: { 'Authorization': 'Bearer ${session.accessToken}' }, ); - Edge函数端:移除非空断言,先检查Authorization头是否存在:
const authHeader = request.headers.get('Authorization'); if (!authHeader) { throw new Error('Authorization header missing'); } const supabaseClient = createClient( supabaseUrl, serviceRoleKey, { global: { headers: { Authorization: authHeader } } } );
- Flutter端:调用函数前先检查当前会话是否存在,避免发送空令牌:
查看Edge函数执行日志
登录Supabase控制台,进入对应的Edge函数页面,查看函数的执行日志,定位具体的错误点(比如获取用户失败、删除用户失败等)。优化Flutter端的错误捕获
可以在catch块中尝试获取响应的原始内容,进一步排查问题:catch (e) { debugPrint(e.toString()); // 尝试获取函数返回的原始响应 try { final response = await supabase.functions.invoke( "delete-user", headers: { 'Authorization': 'Bearer ${supabase.auth.currentSession?.accessToken}' }, ); debugPrint('Raw response: ${response.data}'); } catch (innerE) { debugPrint('Failed to get raw response: ${innerE.toString()}'); } }
内容的提问来源于stack exchange,提问作者Sela404
相关产品推荐
相关产品推荐

