簡體   English   中英

Flutter Web 多部分formdata文件上傳進度條

[英]Flutter Web multipart formdata file upload progress bar

我正在使用 Flutter web 和 strapi 無頭 cms 作為后端。 我能夠成功發送文件,但想要它的進度指示。 后端限制:文件上傳必須是多部分表單數據,可以是緩沖區或 stream。 前端限制: Flutter web 無權訪問系統文件目錄; 文件必須在 memory 中加載並使用其字節發送。

我可以使用顫振的 http package 或 Dio package 上傳文件,但是在嘗試以某種方式訪問上傳進度時出現以下問題:

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 時,它僅在服務器發送完成的請求時響應(即使方法聲明它應該獲得一些進度指示)。

迪歐package代碼

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;
  });

問題:

It seems the package is able to get some progress indication, but Dio package for flutter web has a bug which has not been fixed: requests block the ui and the app freezes until upload is finished.

您好,您可以使用universal_html/html.dart package來做進度條,步驟如下:

  1. 進口通用package
import 'package:universal_html/html.dart' as html;
  1. 來自 html 輸入元素的 Select 文件,而不是使用文件選擇器包
 _selectFile() {
    html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
    uploadInput.multiple = false;
    uploadInput.accept = '.png,.jpg,.glb';
    uploadInput.click();

    uploadInput.onChange.listen((e) {
      _file = uploadInput.files.first;
    });
 }
  1. 將upload_worker.js 創建到web 文件夾中,我的示例是上傳到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);
}
  1. Flutter web 調用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"),
        ),
      ],
    );
  }
}

就是這樣,我希望它可以幫助你。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM