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

Flutter Web生成的PDF上传S3后损坏,如何实现正确上传?

Flutter Web 生成PDF后上传S3损坏解决方案

问题根因

你之前的代码出现PDF损坏的核心原因是:Dio在Web环境下默认会对请求数据做序列化/UTF-8编码处理,直接传入Uint8List会被当成普通文本转码,导致二进制PDF内容被篡改。同时手动设置的Content-Length如果和实际数据长度不匹配,或者和预签名URL的签名规则冲突,也会导致S3接收的文件异常。

步骤1:验证生成的PDF本身有效性

先排除PDF生成环节的问题,用以下代码将生成的Uint8List在Web端直接下载到本地测试:

import 'dart:html' as html;

void verifyPdfValidity(Uint8List pdfBytes) {
  final pdfBlob = html.Blob([pdfBytes], 'application/pdf');
  final downloadUrl = html.Url.createObjectUrlFromBlob(pdfBlob);
  final anchor = html.AnchorElement(href: downloadUrl)
    ..download = 'test_output.pdf'
    ..target = '_blank';
  html.document.body?.append(anchor);
  anchor.click();
  anchor.remove();
  html.Url.revokeObjectUrl(downloadUrl);
}

如果下载的PDF可以正常打开,说明生成环节无问题,问题出在上传流程。

步骤2:修正上传代码

改为以二进制流的形式发送数据,同时禁用Dio的默认请求转换逻辑:

import 'package:dio/dio.dart';

Future<void> uploadPdfToS3(String s3PresignedPutUrl, Uint8List pdfBytes) async {
  final dio = Dio();
  await dio.put(
    s3PresignedPutUrl,
    // 转为Stream发送,避免Dio自动序列化二进制数据
    data: Stream.fromIterable(pdfBytes.map((byte) => [byte])),
    options: Options(
      contentType: 'application/pdf',
      // 直接用PDF数据的实际长度,不要手动传入其他值
      contentLength: pdfBytes.length,
      // 禁用默认请求编码器,避免二进制内容被转码
      requestEncoder: (List<int> data, RequestOptions options) => data,
    ),
    onSendProgress: (sentBytes, totalBytes) {
      if (totalBytes != -1) {
        final progress = sentBytes / totalBytes * 100;
        print('上传进度:${progress.toStringAsFixed(1)}%');
      }
    },
  );
}

注意事项

  • 生成S3预签名PUT URL时,必须指定ContentType为application/pdf,和上传时的contentType完全一致,否则会触发S3签名校验失败,导致文件损坏
  • 不要额外添加未在预签名URL计算时包含的请求头,避免签名不匹配
  • 不需要引入任何文件读写相关的库,直接操作Uint8List即可完成Web端的上传流程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 00:09:03