Flutter Web大文件上传时出现Array buffer分配失败如何解决?
错误原因
你遇到的RangeError: Array buffer allocation failed错误是Flutter Web环境下全量加载大文件到内存导致的:
- 虽然你给
pickFiles开启了withReadStream: true拿到了文件流,但Dart官方http库的MultipartFile在Web端实现时,会提前把整个文件流的内容全部读取到内存的Uint8List中,再生成请求体 - 当上传的文件过大(通常超过500MB,具体阈值取决于浏览器内存限制)时,浏览器无法分配足够大的连续数组缓冲区存储整个文件内容,就会抛出这个错误。
解决方案
方案1:基于浏览器原生API实现流式上传(适合GB级以内文件)
直接调用Web原生的
FormData和HttpRequest能力,不会把整个文件加载到内存,浏览器会自动处理流式上传:import 'dart:html' as html; import 'package:file_picker/file_picker.dart'; // 选完文件后获取原生File对象 List<PlatformFile>? files = fileUploadView.result?.files; if (files == null || files.isEmpty) return; // 创建原生FormData final formData = html.FormData(); for (var file in files) { // Web端PlatformFile的path属性对应原生File对象 html.File nativeFile = file.path as html.File; formData.appendBlob( "你的服务端接收参数名", nativeFile, file.name ); } // 发送请求 final request = html.HttpRequest(); request.open('POST', '你的上传接口地址'); // 按需添加请求头,比如鉴权token request.setRequestHeader('Authorization', 'Bearer your_token'); request.onLoadEnd.listen((_) { if (request.status == 200) { // 上传成功逻辑 print('上传成功: ${request.responseText}'); } else { // 上传失败逻辑 print('上传失败: ${request.status}'); } }); // 监听上传进度(可选) request.upload.onProgress.listen((event) { if (event.lengthComputable) { double progress = event.loaded! / event.total!; print('上传进度: ${(progress * 100).toStringAsFixed(2)}%'); } }); request.send(formData);方案2:分片上传(适合超过2GB的超大文件,支持断点续传)
超过浏览器单次上传大小限制的文件,需要切割成分片逐个上传,后端需要配套支持分片合并、断点校验逻辑:
核心实现逻辑:- 按固定分片大小(通常5MB~20MB)调用原生
File.slice方法切割文件 - 每个分片携带文件唯一标识、分片序号、总分片数参数上传
- 所有分片上传完成后调用后端接口合并分片
分片核心代码示例:
const int chunkSize = 10 * 1024 * 1024; // 10MB每片 html.File nativeFile = file.path as html.File; int totalChunks = (nativeFile.size / chunkSize).ceil(); String fileId = '生成文件唯一标识,比如文件hash+文件名'; for (int i = 0; i < totalChunks; i++) { final start = i * chunkSize; final end = start + chunkSize > nativeFile.size ? nativeFile.size : start + chunkSize; final chunk = nativeFile.slice(start, end); final chunkFormData = html.FormData(); chunkFormData.appendBlob('chunk', chunk, '${fileId}_$i'); chunkFormData.append('fileId', fileId); chunkFormData.append('chunkIndex', i.toString()); chunkFormData.append('totalChunks', totalChunks.toString()); // 发送当前分片请求,可自行添加失败重试、并发控制逻辑 // ... } // 所有分片上传完成后调用合并接口- 按固定分片大小(通常5MB~20MB)调用原生
内容的提问来源于stack exchange,提问作者EinEsellesEniE
相关产品推荐
相关产品推荐

