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

Flutter解码大JSON时随机出现FormatException的排查求助

Flutter JSON解码随机触发FormatException问题

问题现象

  • JSON解码时随机抛出FormatException,错误提示多为缺失引号、冒号、逗号或闭合括号,异常集中在JSON末尾
  • JSON体积≥100KB时开始出现,≥300KB时几乎必现,<100KB也偶发
  • 后端Laravel API经Postman测试返回正常,仅在模拟器中触发异常
  • 已尝试更换Dio/Http库、切换http/https、设置ResponseType.plain、正则处理返回数据,均未解决

Http工具类代码

import 'dart:convert';
import 'package:http/http.dart' as http;

class Http {
  Http._internal();
  static final Http _instance = Http._internal();
  Map<String, String> headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  };
  String baseUrl = 'http://ipv4/api';

  factory Http() {
    return _instance;
  }

  Future<http.Response> get(
    String path, {
    Map<String, dynamic>? queryParameters,
    Map<String, String>? customHeaders,
  }) async {
    final Uri uri =
        Uri.parse('$baseUrl$path').replace(queryParameters: queryParameters);

    final response = await http.get(
      uri,
      headers: {...headers, ...?customHeaders},
    );

    return response;
  }
}

业务解码代码

final token = await _tokenFuture;
final response = await Http().get('/construction', customHeaders: {'Authorization': 'Bearer $token'});
final List<Map<String, dynamic>> jsonList = List<Map<String, dynamic>>.from(json.decode(response.body));

异常示例

  • 键缺失引号:...material":"15000","labor:"10000"...
  • 值缺失引号:...material":"15000","labor":10000"...
  • 缺失逗号:...material":"15000""labor":"10000"...
  • 缺失冒号:...material""15000","labor":"10000"...
  • 缺失闭合括号(暂未确认是否会在中间缺失)

解决方案建议

  1. 检查响应完整性
    打印response.body.length并和后端实际返回的JSON长度对比,确认是否存在响应截断。模拟器网络环境可能存在分片传输时的拼接错误,导致JSON不完整。
  2. 强制指定UTF-8编码解析
    后端返回的JSON可能存在编码不一致问题,手动指定编码避免解析异常:
    final responseBody = utf8.decode(response.bodyBytes);
    final jsonList = List<Map<String, dynamic>>.from(json.decode(responseBody));
    
  3. 启用Gzip压缩
    大体积JSON开启压缩可减少传输数据量,降低截断概率:
    • 后端Laravel通过Nginx或中间件配置Gzip压缩
    • Flutter请求头添加Accept-Encoding: gzip,接收时解压:
      import 'dart:io';
      
      Future<String> _decodeResponse(http.Response response) async {
        if (response.headers['content-encoding'] == 'gzip') {
          final gzipBytes = GZipCodec().decode(response.bodyBytes);
          return utf8.decode(gzipBytes);
        }
        return utf8.decode(response.bodyBytes);
      }
      
  4. 验证JSON合法性
    解码前用工具验证JSON格式,或捕获异常后保存错误响应内容到本地,对比后端正确返回的JSON,定位具体截断或篡改位置。
  5. 检查模拟器网络代理
    若模拟器开启了代理工具(如Charles),可能存在代理对大体积响应的篡改或截断,尝试关闭代理后测试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 18:25:07