Flutter Web 多部分formdata文件上传进度条
Posted
技术标签:
【中文标题】Flutter Web 多部分formdata文件上传进度条【英文标题】:Flutter Web multipart formdata file upload progress bar 【发布时间】:2021-05-18 12:46:12 【问题描述】:我正在使用 Flutter web 和strapi headless cms 作为后端。我能够成功发送文件,但想要它的进度指示。后端限制:文件上传必须是多部分表单数据,可以是缓冲区或流。前端限制:Flutter web 无权访问系统文件目录;文件必须加载到内存中并使用其字节发送。
我可以使用flutter的http包或Dio包上传文件,但是在尝试以某种方式访问上传进度时遇到以下问题:
Http 示例代码:
http.StreamedResponse response;
final uri = Uri.parse(url);
final request = MultipartRequest(
'POST',
uri,
);
request.headers['authorization'] = 'Bearer $_token';
request.files.add(http.MultipartFile.fromBytes(
'files',
_fileToUpload.bytes,
filename: _fileToUpload.name,
));
response = await request.send();
var resStream = await response.stream.bytesToString();
var resData = json.decode(resStream);
我尝试了什么: 当访问 onData 的 response.stream 时,它只在服务器发送完成的请求时做出响应(即使方法声明它应该获得一些进度指示)。
Dio包代码
Response response = await dio.post(url,
data: formData,
options: Options(
headers:
'authorization': 'Bearer $_token',
,
), onSendProgress: (int sent, int total)
setState(()
pm.progress = (sent / total) * 100;
);
问题:
该包似乎能够获得一些进度指示,但 Flutter web 的 Dio 包有一个尚未修复的错误:请求阻塞 ui 并且应用程序冻结直到上传完成。
【问题讨论】:
dio 问题仍未解决:github.com/flutterchina/dio/issues/961github.com/flutterchina/dio/issues/925 【参考方案1】:你好,可以使用universal_html/html.dart包做进度条,步骤如下:
-
导入通用包
import 'package:universal_html/html.dart' as html;
-
从 html 输入元素中选择文件,而不是使用文件选择器包
_selectFile()
html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
uploadInput.multiple = false;
uploadInput.accept = '.png,.jpg,.glb';
uploadInput.click();
uploadInput.onChange.listen((e)
_file = uploadInput.files.first;
);
-
在 web 文件夹中创建 upload_worker.js,我的示例是上传到 S3 post presigned url
self.addEventListener('message', async (event) =>
var file = event.data.file;
var url = event.data.url;
var postData = event.data.postData;
uploadFile(file, url, postData);
);
function uploadFile(file, url, presignedPostData)
var xhr = new XMLHttpRequest();
var formData = new FormData();
Object.keys(presignedPostData).forEach((key) =>
formData.append(key, presignedPostData[key]);
);
formData.append('Content-Type', file.type);
// var uploadPercent;
formData.append('file', file);
xhr.upload.addEventListener("progress", function (e)
if (e.lengthComputable)
console.log(e.loaded + "/" + e.total);
// pass progress bar status to flutter widget
postMessage(e.loaded/e.total);
);
xhr.onreadystatechange = function ()
if (xhr.readyState == XMLHttpRequest.DONE)
// postMessage("done");
xhr.onerror = function ()
console.log('Request failed');
// only triggers if the request couldn't be made at all
// postMessage("Request failed");
;
xhr.open('POST', url, true);
xhr.send(formData);
-
Flutter web call upload worker 上传和监听进度条状态
class Upload extends StatefulWidget
@override
_UploadState createState() => _UploadState();
class _UploadState extends State<Upload>
html.Worker myWorker;
html.File file;
_uploadFile() async
String _uri = "/upload";
final postData = ;
myWorker.postMessage("file": file, "uri": _uri, postData: postData);
_selectFile()
html.InputElement uploadInput = html.FileUploadInputElement();
uploadInput.multiple = false;
uploadInput.click();
uploadInput.onChange.listen((e)
file = uploadInput.files.first;
);
@override
void initState()
myWorker = new html.Worker('upload_worker.js');
myWorker.onMessage.listen((e)
setState(()
//progressbar,...
);
);
super.initState();
@override
Widget build(BuildContext context)
return Column(
children: [
RaisedButton(
onPressed: _selectFile,
child: Text("Select File"),
),
RaisedButton(
onPressed: _uploadFile,
child: Text("Upload"),
),
],
);
就是这样,希望对你有帮助。
【讨论】:
以上是关于Flutter Web 多部分formdata文件上传进度条的主要内容,如果未能解决你的问题,请参考以下文章
将图像/文件上传到 Strapi (Flutter Web)
使用多部分 FormData 获取 POST 时出现 415
下一个 js 应用程序中 formData 的“操作”多部分字段中的 JSON 无效?