Flutter Web无需自定义类解析JSON响应及API调用报错排查
Flutter Web对接带Firebase鉴权的非Firebase API问题解决及数据展示
1. 先搞定XMLHttpRequest错误(核心是CORS跨域问题)
Postman能正常调用但Flutter Web不行,本质是浏览器的同源策略限制——浏览器会拦截跨域请求,除非后端明确允许你的前端域名访问。
后端需要配置CORS规则,至少要做到:
- 允许你Flutter Web运行的域名(比如本地开发的
http://localhost:5000,线上部署的实际域名) - 允许携带
Authorization请求头(因为Firebase鉴权Token是放在这个头里的) - 开放你需要的请求方法(GET/POST等)
举个Node.js/Express后端的配置示例:
const cors = require('cors'); // 替换成你的前端实际地址 const allowedOrigin = 'http://localhost:5000'; app.use(cors({ origin: allowedOrigin, allowedHeaders: ['Authorization', 'Content-Type'], methods: ['GET', 'POST'] }));
2. 正确的Dio调用代码(带Firebase鉴权)
先获取Firebase用户的ID Token,再用Dio发送请求,直接提取响应里的message字段:
import 'package:dio/dio.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'dart:convert'; // 如果后端返回纯文本才需要,默认JSON可省略 Future<String> getDashboardMessage() async { // 先确认用户已登录 final user = FirebaseAuth.instance.currentUser; if (user == null) throw Exception('请先登录'); // 获取Firebase ID Token final idToken = await user.getIdToken(); final dio = Dio(); try { final response = await dio.get( 'https://your-backend-api.com/dashboard', // 替换成你的API地址 options: Options( headers: { 'Authorization': 'Bearer $idToken', // 和Postman里的请求头一致 'Content-Type': 'application/json', }, ), ); if (response.statusCode == 200) { // 直接从响应数据里取message,不用自定义类 // 如果后端返回的是纯文本,就用jsonDecode(response.data)转成Map return response.data['message'] ?? '暂无内容'; } else { throw Exception('请求失败,状态码: ${response.statusCode}'); } } catch (e) { throw Exception('请求出错: $e'); } }
3. 在UI里展示响应内容
用FutureBuilder处理异步请求,覆盖加载、错误、成功三种状态:
import 'package:flutter/material.dart'; class DashboardPage extends StatelessWidget { const DashboardPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('我的仪表盘')), body: Center( child: FutureBuilder<String>( future: getDashboardMessage(), builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.waiting: return const CircularProgressIndicator(); // 加载中 case ConnectionState.done: if (snapshot.hasError) { return Text('加载失败: ${snapshot.error}', style: const TextStyle(color: Colors.red)); } else if (snapshot.hasData) { return Text(snapshot.data!, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500)); } default: return const Text('暂无数据'); } }, ), ), ); } }
4. 额外排查点
- 如果提取数据时还是报错:检查后端返回的
Content-Type是否为application/json,如果是纯文本,要先用jsonDecode(response.data)转成Map再取值 - 验证Firebase Token有效性:可以用Firebase官方的Token验证工具确认Token是否合法
- 确保Dio是最新稳定版:避免版本兼容性问题
内容的提问来源于stack exchange,提问作者Hunter Books
相关产品推荐
相关产品推荐

