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

Flutter中HTTP请求数据转List对象始终为空问题求助

Flutter HTTP请求获取数据后List始终为空的问题排查与解决

问题描述

我是Flutter新手,具备C#开发背景。在通过HTTP请求获取站点数据并转换为List<Stations>对象时,尽管响应体包含有效数据,但List始终为空。调试阶段可观察到响应体中的内容,相关实现代码如下:

HttpService代码

class HttpService {
  final String url = "url hidden";
  final String host = 'url hidden';
  final String apiSegment = "api/";

// ignore: non_constant_identifier_names
  void login(email, password) async {
    try {
      Map<String, String> body = {
        'username': email,
        'password': password,
      };

      Map<String, String> headers = {'Content-Type': 'application/json'};
      final msg = jsonEncode(body);

      Response response =
          await post(Uri.parse("$url/Login"), headers: headers, body: msg);

      if (response.statusCode == 200) {
        var data = jsonDecode(response.body.toString());
        print(data['jwtToken']);
        print('Login successfully');

        final prefs = await SharedPreferences.getInstance();

        await prefs.setString('jwtToken', data['jwtToken']);

        List<Stations> stationData = await getStationData('11');
        var test = stationData;
      } else {
        print('failed');
      }
    } catch (e) {
      print(e.toString());
    }
  }

  Future<List<Stations>> getStationData(String stationId) async {
    final prefs = await SharedPreferences.getInstance();
    final String? token = prefs.getString('jwtToken');
    const String path = 'Station/GetAllStationData';

    final uri = Uri.parse('$url/api/$path')
        .replace(queryParameters: {'stationId': stationId});

    List<Stations> stationData = <Stations>[];
    try {
      Response res = await get(uri, headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        // 'Authorization': 'Bearer $token',
      });

      if (res.statusCode == 200) {
        var body = jsonDecode(res.body);
        var body2 = body.toString();

        stationData = body
            .map(
              (dynamic item) => Stations.fromJson(item),
            )
            .toList();
      } else {
        throw "Unable to retrieve posts.";
      }
    } catch (e) {
      print(e.toString());
    }
    return stationData;
  }
}

调用方式

List<Stations> stationData = await getStationData('11');

响应体结构

响应体为外层包含data字段的JSON对象,data字段对应站点数据数组(示例结构如下):

{
  "data": [
    {"id": "1", "name": "站点1", ...},
    {"id": "2", "name": "站点2", ...}
  ]
}

问题原因

直接对jsonDecode(res.body)返回的整个JSON对象调用map方法,但该对象并非数组,而是包含data数组的外层对象。这种操作会触发异常,被catch块捕获后,最终返回初始的空列表。

解决方案

1. 修正数据转换逻辑

在解析响应体时,先提取data字段对应的数组,再进行对象转换:

if (res.statusCode == 200) {
  var body = jsonDecode(res.body);
  // 提取data字段的数组
  var stationJsonList = body['data'] as List;
  stationData = stationJsonList
      .map((dynamic item) => Stations.fromJson(item))
      .toList();
}

2. 增强错误排查能力

在catch块中打印详细错误信息,方便定位问题:

catch (e, stackTrace) {
  print('获取站点数据异常: $e');
  print('异常堆栈: $stackTrace');
}

3. 验证Stations.fromJson方法

确保Stations类的fromJson方法正确映射JSON字段,尤其是注意C#习惯的PascalCase和Dart小驼峰命名的差异。推荐使用json_annotation包自动生成序列化代码,避免手动映射出错:

  • 添加依赖:json_annotation: ^4.8.1、build_runner: ^2.4.4、json_serializable: ^6.7.1
  • 定义Stations类并添加注解:
import 'package:json_annotation/json_annotation.dart';

part 'stations.g.dart';

@JsonSerializable()
class Stations {
  final String id;
  final String name;
  // 其他字段...

  Stations({required this.id, required this.name, ...});

  factory Stations.fromJson(Map<String, dynamic> json) => _$StationsFromJson(json);
  Map<String, dynamic> toJson() => _$StationsToJson(this);
}
  • 运行命令生成序列化代码:flutter pub run build_runner build

4. 其他注意事项

  • 如果接口需要身份验证,取消Authorization头的注释,确保token正确传递:'Authorization': 'Bearer $token'
  • 调试时可打印body['data']的内容,确认数组结构和字段是否符合预期。

内容的提问来源于stack exchange,提问作者dotnetdevcsharp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:20:28