Flutter中FutureBuilder snapshot.data为空及Dio请求错误解决
解决Flutter中FutureBuilder的snapshot.data为空及Dio XMLHttpRequest错误问题
问题描述
我在Flutter项目中使用data.dart类封装Dio请求获取学生数据,但通过FutureBuilder调用时出现snapshot.data为null的情况。不过将相关代码用简单main函数单独运行时,该问题并未出现。调试控制台提示错误:Error: DioError [DioErrorType.response]: XMLHttpRequest error。
相关代码
主代码
import 'package:flutter/material.dart'; import 'package:flutter_application_1/data.dart'; void main() { getStudents(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const HomeScreen(), ); } } class HomeScreen extends StatelessWidget{ const HomeScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Android Expert'),), body:FutureBuilder<List<StudentData>?>(future: getStudents(), builder:(context, snapshot) { if(snapshot.hasData){ return ListView.builder( itemCount: snapshot.data!.length, itemBuilder: (context, index) { return Container(height: 84, color: Colors.red, margin:EdgeInsets.fromLTRB(8, 4, 8, 4)); }, ); } else{ return Center(child:CircularProgressIndicator(),); } },) ); } }
data.dart代码
import 'package:dio/dio.dart'; class StudentData{ final int id; final String firstName; final String lastName; final String course; final int score; final String createdAt; final String updatedAt; StudentData(this.id, this.firstName, this.lastName, this.course, this.score, this.createdAt, this.updatedAt); StudentData.fromJson(Map<String, dynamic> json) : id = json['id'], firstName = json['first_name'], lastName = json['last_name'], course = json['course'], score = json['score'], createdAt = json['created_at'], updatedAt = json['created_at']; } class HttpClient{ static Dio instance=Dio(BaseOptions(baseUrl: 'http://expertdevelopers.ir/api/v1/')); } Future<List<StudentData>?> getStudents()async{ final response=await HttpClient.instance.get('experts/student'); final List<StudentData> students=[]; if (response.data is List<dynamic>){ (response.data as List<dynamic>).forEach((element) { students.add(StudentData.fromJson(element)); }); } //print(students.toString()); return students; }
解决方案
1. 处理跨域(XMLHttpRequest error核心原因)
这个错误大多出现在Flutter Web环境中,是跨域资源访问限制导致的:
- 后端需配置CORS,允许前端域名的请求;
- 本地开发时,可通过
flutter run --web-port 5000 --web-hostname 0.0.0.0启动项目,同时确保后端服务已开启并允许该端口访问。
2. 修正FutureBuilder的错误用法
当前在build方法中直接调用getStudents(),每次Widget重建都会重复发起请求,还可能导致状态混乱。应将Future对象存入State中,只初始化一次:
class HomeScreen extends StatefulWidget { const HomeScreen({Key? key}) : super(key: key); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { late Future<List<StudentData>?> _studentsFuture; @override void initState() { super.initState(); _studentsFuture = getStudents(); // 仅初始化时请求一次 } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Android Expert')), body: FutureBuilder<List<StudentData>?>( future: _studentsFuture, builder: (context, snapshot) { // 新增错误状态处理 if (snapshot.hasError) { return Center(child: Text('请求失败: ${snapshot.error}')); } if (snapshot.hasData) { final students = snapshot.data!; return ListView.builder( itemCount: students.length, itemBuilder: (context, index) { final student = students[index]; return Container( height: 84, color: Colors.red, margin: const EdgeInsets.fromLTRB(8, 4, 8, 4), child: Padding( padding: const EdgeInsets.all(8.0), child: Text('${student.firstName} ${student.lastName}'), ), ); }, ); } else { return const Center(child: CircularProgressIndicator()); } }, ), ); } }
3. 给Dio请求添加错误捕获
避免请求异常导致Future返回null,在getStudents中加入try-catch:
Future<List<StudentData>?> getStudents() async { try { final response = await HttpClient.instance.get('experts/student'); final List<StudentData> students = []; if (response.data is List<dynamic>) { (response.data as List<dynamic>).forEach((element) { students.add(StudentData.fromJson(element)); }); } return students; } on DioError catch (e) { print('Dio请求错误: ${e.message}'); return []; // 可返回空列表,避免snapshot.data为null } catch (e) { print('未知错误: $e'); return null; } }
4. 修复StudentData.fromJson的字段错误
原代码中updatedAt赋值错误,修正为正确的字段名:
StudentData.fromJson(Map<String, dynamic> json) : id = json['id'], firstName = json['first_name'], lastName = json['last_name'], course = json['course'], score = json['score'], createdAt = json['created_at'], updatedAt = json['updated_at']; // 修正为updated_at字段
内容的提问来源于stack exchange,提问作者atishn90
相关产品推荐
相关产品推荐

