You need to enable JavaScript to run this app. Flutter Web从Apache服务端拉取媒体文件的最优实现方案是什么
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Web从Apache服务端拉取媒体文件的最优实现方案是什么

问题根因

你当前使用ResponseType.bytes的配置,会将整份文件的二进制数据全部加载到Dart虚拟机内存后再调用saveAs导出,当文件体积超过浏览器分配给当前标签页的内存配额时,就会触发内存溢出错误。

推荐解决方案

方案1:流式下载(支持自定义进度、取消逻辑,适配大文件场景)

改用流响应模式,边下载边写入浏览器下载管道,全程不会加载全量文件到内存,内存占用稳定在KB级,可支持GB级文件下载。

修改后代码示例:

import 'package:dio/dio.dart';
import 'package:stream_saver/stream_saver.dart'; // 可直接使用pub上封装好的stream_saver包,或自行通过dart:js_interop对接StreamSaver API

// 下载逻辑
Future<void> downloadFile(String medialink, CancelToken cancelToken) async {
  final response = await dio.get(
    medialink,
    cancelToken: cancelToken,
    onReceiveProgress: (rcv, total) {
      if (total != -1) {
        setState(() {
          progress = ((rcv / total) * 100).toStringAsFixed(0);
        });
        if (rcv == total) {
          setState(() {
            isDownloaded = true;
            downloading = false;
          });
        }
      }
    },
    options: Options(
      responseType: ResponseType.stream, // 改为流响应,不加载全量字节
      followRedirects: false,
      validateStatus: (status) => status! < 500,
    ),
  );

  // 从响应头获取文件名,也可自定义
  final contentDisposition = response.headers.value('content-disposition');
  String filename = 'download_file';
  if (contentDisposition != null) {
    final matches = RegExp(r'filename="?([^"]+)"?').firstMatch(contentDisposition);
    if (matches != null) {
      filename = Uri.decodeFull(matches.group(1)!);
    }
  }

  // 直接将响应流写入下载管道
  final writer = createWriteStream(filename).getWriter();
  await for (final chunk in response.data.stream) {
    await writer.write(chunk);
  }
  await writer.close();
}

前置配置:

  • Apache服务端需要添加响应头配置Access-Control-Expose-Headers: Content-Length, Content-Disposition,否则进度计算和文件名获取会失效
  • 若需要支持断点续传,可在请求头中添加Range字段,配合Apache默认开启的范围请求能力实现

方案2:原生浏览器下载(无自定义需求时最简实现)

如果不需要自定义进度展示、下载取消等逻辑,直接调用浏览器原生下载能力,完全由浏览器内核处理下载逻辑,不会存在内存溢出问题。

代码示例:

import 'dart:html' as html;

void downloadFile(String medialink, String filename) {
  final anchor = html.AnchorElement(href: medialink);
  anchor.download = filename;
  anchor.click();
  anchor.remove();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 14:06:03