You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 06:10:30