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

Flutter HTTP请求jsonDecode空异常及连接超时问题修复

问题修复与规避方案

一、JSON解析空异常修复

不确定的空异常通常是因为响应结构不稳定、深层嵌套字段为空,或是手动解析时的疏漏,仅靠?或!无法完全覆盖场景,可按以下方式修复:

  • 用强类型模型替代手动解析
    借助json_serializable生成模型类,自动处理空值映射,避免手动取值的错误:

    1. 添加依赖到pubspec.yaml:
      dependencies:
        json_annotation: ^4.8.1
      dev_dependencies:
        build_runner: ^2.4.4
        json_serializable: ^6.7.0
      
    2. 定义城市响应模型:
      import 'package:json_annotation/json_annotation.dart';
      
      part 'city_response.g.dart';
      
      @JsonSerializable()
      class CityResponse {
        final String? cityName;
        final double? latitude;
        final double? longitude;
        // 按需添加其他字段,用?标记可空属性
      
        CityResponse({this.cityName, this.latitude, this.longitude});
      
        factory CityResponse.fromJson(Map<String, dynamic> json) => _$CityResponseFromJson(json);
        Map<String, dynamic> toJson() => _$CityResponseToJson(this);
      }
      
    3. 运行代码生成命令:
      flutter pub run build_runner build
      

    解析时直接调用CityResponse.fromJson(jsonDecode(response.body)),模型会自动处理空字段,避免手动取值的空指针问题。

  • 添加响应完整性校验
    在解析前先校验响应的合法性:

    final response = await http.get(Uri.parse(url));
    if (response.statusCode != 200) {
      throw Exception('请求失败,状态码:${response.statusCode}');
    }
    if (response.body.isEmpty) {
      throw Exception('响应体为空');
    }
    final jsonData = jsonDecode(response.body);
    // 校验核心字段是否存在
    if (jsonData is! Map || !jsonData.containsKey('cityName')) {
      throw Exception('响应结构不符合预期');
    }
    
  • 避免滥用!操作符
    即使认为字段必然存在,也用??提供默认值,兜底空值场景:

    final cityName = jsonData['cityName'] ?? '未知城市';
    

二、连接超时问题规避方案

针对dreamhost.com跨区域连接质量差的问题,可通过以下方式优化:

  • 设置请求超时时间
    为HTTP请求明确设置超时,避免无限等待:

    try {
      final response = await http.get(Uri.parse(url)).timeout(const Duration(seconds: 10));
      // 处理响应逻辑
    } on TimeoutException {
      // 超时处理:提示用户或触发重试
      print('请求超时,请稍后重试');
    } on SocketException {
      // 网络连接异常处理
      print('网络连接失败,请检查网络状态');
    }
    
  • 实现有限次数的请求重试
    针对超时或连接失败的情况,自动重试2-3次:

    Future<http.Response> fetchWithRetry(String url, int retryCount) async {
      try {
        return await http.get(Uri.parse(url)).timeout(const Duration(seconds: 10));
      } catch (e) {
        if (retryCount > 0) {
          await Future.delayed(const Duration(seconds: 2));
          return fetchWithRetry(url, retryCount - 1);
        }
        rethrow;
      }
    }
    // 使用示例:最多重试2次
    // final response = await fetchWithRetry(url, 2);
    
  • 缓存查询结果
    用本地缓存(如shared_preferences或Hive)存储相同经纬度的查询结果,一段时间内重复查询直接读取缓存,减少HTTP请求次数:

    final cacheKey = 'city_${lat}_${lng}';
    final prefs = await SharedPreferences.getInstance();
    final cachedData = prefs.getString(cacheKey);
    
    if (cachedData != null) {
      return CityResponse.fromJson(jsonDecode(cachedData));
    }
    
    // 发起请求并缓存结果
    final response = await fetchWithRetry(url, 2);
    final cityData = CityResponse.fromJson(jsonDecode(response.body));
    await prefs.setString(cacheKey, jsonEncode(cityData));
    return cityData;
    
  • 切换请求节点(若可行)
    如果有权限,可为dreamhost的服务配置全球CDN,或在客户端使用就近的代理节点转发请求,降低跨区域网络延迟。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 22:10:21