Flutter HTTP请求jsonDecode空异常及连接超时问题修复
问题修复与规避方案
一、JSON解析空异常修复
不确定的空异常通常是因为响应结构不稳定、深层嵌套字段为空,或是手动解析时的疏漏,仅靠?或!无法完全覆盖场景,可按以下方式修复:
用强类型模型替代手动解析
借助json_serializable生成模型类,自动处理空值映射,避免手动取值的错误:- 添加依赖到
pubspec.yaml:dependencies: json_annotation: ^4.8.1 dev_dependencies: build_runner: ^2.4.4 json_serializable: ^6.7.0 - 定义城市响应模型:
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); } - 运行代码生成命令:
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
相关产品推荐
相关产品推荐

