Flutter使用Dio下载PDF遇HTTP 400错误的排查求助
Flutter中使用Dio下载PDF时出现HTTP 400错误
错误信息
E/flutter (14805): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: DioError [DioErrorType.response]: Http status error [400] E/flutter (14805): Source stack: E/flutter (14805): #0 DioMixin.fetch (package:dio/src/dio_mixin.dart:488:35) E/flutter (14805): #1 DioMixin.request (package:dio/src/dio_mixin.dart:483:12) E/flutter (14805): #2 DioForNative.download (package:dio/src/entry/dio_for_native.dart:84:24) E/flutter (14805): #3 OpenBalanceController.getOpenBalancePDF (package:otrack/views/reports/controllers/open_balance_controller.dart:143:26) E/flutter (14805): <asynchronous suspension> E/flutter (14805): E/flutter (14805): #0 DioMixin.fetch.<anonymous closure> (package:dio/src/dio_mixin.dart:643:7) E/flutter (14805): #1 _RootZone.runBinary (dart:async/zone.dart:1665:54) E/flutter (14805): #2 _FutureListener.handleError (dart:async/future_impl.dart:162:22) E/flutter (14805): #3 Future._propagateToListeners.handleError (dart:async/future_impl.dart:779:47) E/flutter (14805): #4 Future._propagateToListeners (dart:async/future_impl.dart:800:13) E/flutter (14805): #5 Future._completeError (dart:async/future_impl.dart:575:5) E/flutter (14805): #6 _SyncCompleter._completeError (dart:async/future_impl.dart:51:12) E/flutter (14805): #7 _Completer.completeError (dart:async/future_impl.dart:23:5) E/flutter (14805): #8 Future.any.onError (dart:async/future.dart:617:45) E/flutter (14805): #9 _RootZone.runBinary (dart:async/zone.dart:1665:54) E/flutter (14805): #10 _FutureListener.handleError (dart:async/future_impl.dart:162:22) E/flutter (14805): #11 Future._propagateToListeners.handleError (dart:async/future_impl.dart:779:47) E/flutter (14805): #12 Future._propagateToListeners (dart:async/future_impl.dart:800:13) E/flutter (14805): #13 Future._completeError (dart:async/future_impl.dart:575:5) E/flutter (14805): #14 Future._asyncCompleteError.<anonymous closure> (dart:async/future_impl.dart:666:7) E/flutter (14805): #15 _microtaskLoop (dart:async/schedule_microtask.dart:40:21) E/flutter (14805): #16 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)
我的Dio接口代码
Future getOpenBalancePDF() async { isLoading.value = true; final headers = await BaseClient.generateHeaders(); Dio dioWithHeaders = Dio(BaseOptions( receiveTimeout: 999999, sendTimeout: 999999, headers: headers)); var dir = await getApplicationDocumentsDirectory(); String path = "${dir.path}/TransactionSummary.pdf"; final data = FormData.fromMap({ "orderType": 0, "fromDate": "2000-01-01", "toDate": "2023-12-01", "customerFilterList": [1387, 1460], "exportFormat": 1, "openBalance": true }); await dioWithHeaders.download( ApiConstants.POST_CUSTOMER_OPEN_BALANCE_REPORT, data: data, (Headers headers) { headers.map.values; return path; }, ); if (path.isNotEmpty) { Get.to( () => PDFScreen( path: path, ), ); } isLoading.value = false; }
补充说明
该API在Postman中可正常运行,请求头包含必要鉴权信息,请求体为FormData格式,响应返回PDF文件流。
问题分析与解决方法
核心问题
- Dio download方法参数传递错误:download的第二个参数应为文件保存路径,你错误地将
data: data作为命名参数传入,且第三个参数的函数不符合onReceiveProgress的签名要求。 - 请求方法不匹配:Dio的
download方法默认使用GET请求,但你的API需要POST请求(从接口命名及Postman请求方式可判断),GET请求无法携带FormData请求体,导致服务端返回400错误。
修正后的代码
使用post请求获取文件流,再写入本地文件:
Future getOpenBalancePDF() async { isLoading.value = true; try { final headers = await BaseClient.generateHeaders(); Dio dioWithHeaders = Dio(BaseOptions( receiveTimeout: 999999, sendTimeout: 999999, headers: headers )); var dir = await getApplicationDocumentsDirectory(); String path = "${dir.path}/TransactionSummary.pdf"; final data = FormData.fromMap({ "orderType": 0, "fromDate": "2000-01-01", "toDate": "2023-12-01", "customerFilterList": [1387, 1460], "exportFormat": 1, "openBalance": true }); // 发送POST请求,以流形式接收响应 Response response = await dioWithHeaders.post( ApiConstants.POST_CUSTOMER_OPEN_BALANCE_REPORT, data: data, options: Options(responseType: ResponseType.stream), ); // 将响应流写入本地文件 File file = File(path); IOSink sink = file.openWrite(); await sink.addStream(response.data.stream); await sink.close(); if (await file.exists()) { Get.to(() => PDFScreen(path: path)); } } catch (e) { // 捕获并处理错误 print("下载失败: $e"); } finally { isLoading.value = false; } }
额外检查项
- 确认
BaseClient.generateHeaders()生成的请求头与Postman完全一致,特别是Authorization字段。 - 验证请求体中的参数格式(如日期格式、数组结构)是否与Postman完全匹配,避免因参数类型不匹配被服务端拒绝。
内容的提问来源于stack exchange,提问作者Ahmed Raza
相关产品推荐
相关产品推荐

