Flutter从API获取PDF响应后生成打开PDF遇类型转换错误求助
解决PDF二进制数据转文件的类型不匹配问题
问题根源
Retrofit默认会把API响应解析为UTF-8字符串,但PDF属于二进制文件,直接解析成字符串不仅会损坏数据,还会和writeAsBytes方法要求的List<int>类型不兼容,从而抛出type 'String' is not a subtype of type 'List<int>'错误。
解决方案及修改代码
1. 修改Retrofit接口,指定返回二进制字节流
调整接口的返回类型,并强制Dio以二进制形式接收响应:
import 'package:dio/dio.dart'; import 'package:retrofit/retrofit.dart'; part 'invoice_remote_data_source.g.dart'; @RestApi() abstract class InvoiceRemoteDataSource { factory InvoiceRemoteDataSource( Dio dio, { String baseUrl, }) = _InvoiceRemoteDataSource; @POST('/download_invoice_pdf') @Headers({ 'Accept': 'application/pdf', }) Future<Response<List<int>>> downloadInvoicePDF({ @Field("session_token") required String sessionToken, @Field("user_id") required String userId, @Field("invoice_id") required String invoiceId, @Options(responseType: ResponseType.bytes) Options? options, }); }
2. 调整业务逻辑,使用正确的字节数据写入文件
修正文件路径的错误(移除多余引号),并确保传入writeAsBytes的是List<int>类型:
@override Future<Either<Failure, dynamic>> getInvoicePDF(GetInvoiceParams param) async { return await Factory().exceptionsGuard(() async { var res = await RemoteDataSourceResponseGuard.execute<Response<List<int>>>( _invoiceRemoteDataSource.downloadInvoicePDF( sessionToken: param.sessionToken, userId: param.userId, invoiceId: param.invoiceId, options: Options(responseType: ResponseType.bytes), ), ); await generatePDF(res.data!); }); } Future generatePDF(List<int> value) async { debugPrint("file response length: ${value.length}"); String dir = (await getApplicationDocumentsDirectory()).path; // 移除路径中的多余引号,避免无效路径 File file = File('$dir/file.pdf'); await file.writeAsBytes(value); try { await OpenFilex.open(file.path); } catch (e) { debugPrint("error opening file: $e"); } }
关键说明
- 通过
responseType: ResponseType.bytes配置,Dio会直接返回原始的二进制字节流,跳过字符串解析步骤,保证PDF数据的完整性。 - 修正后的文件路径避免了因引号导致的文件创建失败问题,确保后续能正常打开生成的PDF。
内容的提问来源于stack exchange,提问作者John Joe
相关产品推荐
相关产品推荐

