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

Flutter调用API获取用户列表失败,控制台报文件不存在错误

问题分析与解决方案

问题描述

尝试从指定API获取用户列表,界面无数据显示;控制台输出E/LB (26008): fail to open file: No such file or directory;打印response.statusCode无输出。

提供的代码

API配置

class ApiSetting{
  static const String _baseUri='http://demo-api.mr-dev.tech/api/';
  static const String users= '${_baseUri}users';
}

User模型

class User {
  late int id;
  late String firstName;
  late String lastName;
  late String email;
  late String mobile;
  late String bio;
  late String jobTitle;
  late String latitude;
  late String longitude;
  late String country;
  late String image;
  late String active;
  late String emailVerifiedAt;
  late String imagesCount;

  User.fromJson(Map<String, dynamic> json) {
    id = json['id'];
    firstName = json['first_name'];
    lastName = json['last_name'];
    email = json['email'];
    mobile = json['mobile'];
    bio = json['bio'];
    jobTitle = json['job_title'];
    latitude = json['latitude'];
    longitude = json['longitude'];
    country = json['country'];
    image = json['image'];
    active = json['active'];
    emailVerifiedAt = json['email_verified_at'];
    imagesCount = json['images_count'];
  }
}

API控制器

import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:api_secand_project/api/api_setting.dart';
import 'package:api_secand_project/models/user.dart';

class UserApiController {
  Future<List<User>> getUser() async {
    var uri = Uri.parse(ApiSetting.users);
    var response = await http.get(uri);
    if (response.statusCode == 200) {
    print(response.statusCode);
      var jsonResponse = jsonDecode(response.body);
      var userJsonArray = jsonResponse['data'] as List;
      return userJsonArray
          .map((jsonObject) => User.fromJson(jsonObject))
          .toList();
    }
    return [];
  }
}

界面代码

import 'package:api_secand_project/api/controllers/user_api_controller.dart';
import 'package:api_secand_project/models/user.dart';
import 'package:flutter/material.dart';

class UsersScreen extends StatefulWidget {
  const UsersScreen({Key? key}) : super(key: key);

  @override
  State<UsersScreen> createState() => _UsersScreenState();
}

class _UsersScreenState extends State<UsersScreen> {

  List<User> _users=<User>[];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Users'),
        ),
        body: FutureBuilder<List<User>>(
          future: UserApiController().getUser(),
          builder: (context, snapshot) {
            if(snapshot.connectionState == ConnectionState.waiting){
              return const Center(
                child: CircularProgressIndicator(),
              );
            }
            else if(snapshot.hasData){
              _users=snapshot.data!;
              return ListView.builder(
                itemCount: _users.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    leading: CircleAvatar(
                      radius: 30,
                      // child: NetworkImage(snapshot.data!.),
                    ),
                    title: Text(_users[index].firstName),
                    subtitle: Text(_users[index].mobile),
                  );
                },
              );
            }
            else{
              return Center(child: Text('No Data',style: TextStyle(fontWeight: FontWeight.bold,fontSize: 28),),);
            }
          },
        ));
  }
}

可能原因及解决方案

1. 网络请求未处理异常与非200状态

  • 原因:代码仅处理statusCode == 200的情况,若请求抛出异常(如网络断开、域名无法解析),会直接终止流程,既不会执行print,也不会返回有效数据;非200状态直接返回空列表,无法排查问题。
  • 解决方案:在API控制器中添加异常捕获,并打印所有状态码和错误信息:
class UserApiController {
  Future<List<User>> getUser() async {
    try {
      var uri = Uri.parse(ApiSetting.users);
      var response = await http.get(uri);
      // 打印所有状态码,方便排查
      print('Response status: ${response.statusCode}');
      if (response.statusCode == 200) {
        var jsonResponse = jsonDecode(response.body);
        var userJsonArray = jsonResponse['data'] as List;
        return userJsonArray.map((jsonObject) => User.fromJson(jsonObject)).toList();
      } else {
        // 打印非200状态的响应体
        print('Response body: ${response.body}');
        return [];
      }
    } catch (e) {
      // 捕获并打印异常信息
      print('Request error: $e');
      return [];
    }
  }
}

2. Android明文HTTP限制

  • 原因:Android 9(API级别28)及以上默认禁止明文HTTP请求,API使用http://协议会被系统拦截,这是请求失败的核心原因。
  • 解决方案:
    • 方法一:在android/app/src/main/AndroidManifest.xml的<application>标签中添加属性:
      <application
          ...
          android:usesCleartextTraffic="true">
          ...
      </application>
      
    • 方法二:若API支持HTTPS,将ApiSetting中的_baseUri改为https://demo-api.mr-dev.tech/api/。

3. FutureBuilder错误处理缺失

  • 原因:当前FutureBuilder仅判断hasData,未处理请求失败(hasError)的情况,异常时界面仍显示"No Data",无法直观看到错误。
  • 解决方案:添加错误处理分支:
builder: (context, snapshot) {
  if(snapshot.connectionState == ConnectionState.waiting){
    return const Center(child: CircularProgressIndicator());
  }
  else if(snapshot.hasData){
    _users=snapshot.data!;
    return _users.isEmpty 
        ? const Center(child: Text('暂无数据'))
        : ListView.builder(
            itemCount: _users.length,
            itemBuilder: (context, index) {
              return ListTile(
                leading: CircleAvatar(
                  radius: 30,
                  backgroundImage: NetworkImage(_users[index].image),
                ),
                title: Text(_users[index].firstName),
                subtitle: Text(_users[index].mobile),
              );
            },
          );
  }
  else if(snapshot.hasError){
    // 显示错误信息
    return Center(child: Text('请求失败: ${snapshot.error}', textAlign: TextAlign.center,));
  }
  else{
    return const Center(child: Text('No Data',style: TextStyle(fontWeight: FontWeight.bold,fontSize: 28),));
  }
}

4. FutureBuilder重复发起请求

  • 原因:每次build方法执行时都会创建新的UserApiController().getUser(),导致重复发起网络请求,可能引发异常或数据混乱。
  • 解决方案:将Future初始化放在initState中:
class _UsersScreenState extends State<UsersScreen> {
  List<User> _users=<User>[];
  late Future<List<User>> _futureUsers;

  @override
  void initState() {
    super.initState();
    // 仅在初始化时发起一次请求
    _futureUsers = UserApiController().getUser();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: const Text('Users')),
        body: FutureBuilder<List<User>>(
          future: _futureUsers, // 使用初始化的Future
          builder: (context, snapshot) {
            // ... 原有builder逻辑
          },
        ));
  }
}

关于控制台的fail to open file日志

该日志与API请求无关,属于系统或其他模块的日志,无需处理。


内容的提问来源于stack exchange,提问作者ِAhmad Shaheen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:30:49