选择一个文件并使用 Flutter Web 通过 POST 发送

Posted

技术标签:

【中文标题】选择一个文件并使用 Flutter Web 通过 POST 发送【英文标题】:Choose a File and send through POST with Flutter Web 【发布时间】:2020-05-02 20:12:18 【问题描述】:

问题陈述

嗨,基本上,我想要的是通过 POST 将文件发送到 python 服务器端 Flask API。

目标是为用户提供一个文件选择器界面,在他/她选择所需的.txt 文件后,使用 POST 请求通过 Dio 发送它。

一个按钮(Widget)应该调用这个uploadFile()函数,一切都应该由它处理


代码

这是我当前的代码:

import 'package:dio/dio.dart';
import 'dart:html';
import 'package:http/http.dart' as http;

BaseOptions options = new BaseOptions(
  baseUrl: "http://localhost:5000",
  connectTimeout: 5000,
  receiveTimeout: 3000,
);
InputElement uploadInput = FileUploadInputElement();

void uploadFile() async 
  uploadInput.click();
  uploadInput.onChange.listen((e) 
    // read file content as dataURL
    final files = uploadInput.files;
    final reader = new FileReader();

    if (files.length == 1) 
      final file = files[0];

        reader.onLoad.listen((e) 
          sendFile(reader.result);
        );

        reader.readAsDataUrl(file);
      
  );


sendFile(file) 
  var dio = new Dio(options);
  FormData formData = FormData.fromMap("file": MultipartFile.fromBytes(file), "fileName": 'data.txt');
  dio.post('/upload', data: formData);
  //dio.post('/upload', data: FormData.fromMap('file': 'aaaa'));


试验结果

这里的问题是 FileReader 没有 readAsBytes 方法,因此我无法使用 fromBytes 方法将文件作为 Multipart 文件发送。

FileReader 的唯一方法是:readAsDataUrlreadAsArrayBufferreadAsText 我不想阅读 .txt 正文来发送它,我想发送实际文件。

其他尝试

我也试过用file_picker,但是好像不支持Flutter Web

参考链接

我的尝试基于:Is there any plugin or way to upload file to server using flutter web?

还有一些我再也找不到了。

反应灵感

我在 React 中设法做到的方式是:

FileUploader.js

export const UploadButton = ( handler ) => (
    <button onClick=handler.uploadTextFile>Upload Image</button>
);

export const FileChooser = ( handler ) => (
    <input
        ref=ref => 
            handler.uploadInput = ref;
        
        type="file"
    />
);

Handler.js:

async uploadTextFile(ev) 
        ev.preventDefault();

        this.fileName = uuid.v4();
        const data = new FormData();
        data.append("file", this.uploadInput.files[0]);
        data.append("fileName", this.fileName);
        data.append("setOfWords", this.words);

        await fetch("http://localhost:5000/upload", 
            method: "POST",
            body: data
        );

请帮忙?我被困在上面超过 4 天,还不知道如何在 Flutter Web 中解决这个问题......

【问题讨论】:

【参考方案1】:

设法做到了:

如blog post中所述:

1.我已将 FileReader 读取为 DataUrl

reader.readAsDataUrl(file);

2。处理数据,将其转换为字节

  Uint8List _bytesData =
      Base64Decoder().convert(file.toString().split(",").last);
  List<int> _selectedFile = _bytesData;

3.要阅读它,请使用Multipart.readFromBytes()

file = http.MultipartFile.fromBytes('file', _selectedFile,
          contentType: new MediaType('application', 'octet-stream'),
          filename: "text_upload.txt")

4.要发送它,请使用 http.request

var url = Uri.parse("http://localhost:5000/upload");
var request = new http.MultipartRequest("POST", url);

request.files.add(http.MultipartFile.fromBytes('file', _selectedFile,
      contentType: new MediaType('application', 'octet-stream'),
      filename: "text_upload.txt"));

request.send().then((response) 
    print("test");
    print(response.statusCode);
    if (response.statusCode == 200) print("Uploaded!");
);

最终代码如下所示

import 'dart:convert';
import 'dart:typed_data';
import 'dart:html';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';

InputElement uploadInput = FileUploadInputElement();

void uploadFile() async 
  uploadInput.draggable = true;
  uploadInput.click();
  uploadInput.onChange.listen((e) 
    // read file content as dataURL
    final files = uploadInput.files;
    final reader = new FileReader();

    if (files.length == 1) 
      final file = files[0];

      reader.onLoad.listen((e) 
        sendFile(reader.result);
      );

      reader.readAsDataUrl(file);
    
  );


sendFile(file) 
  var url = Uri.parse("http://localhost:5000/upload");
  var request = new http.MultipartRequest("POST", url);
  Uint8List _bytesData =
      Base64Decoder().convert(file.toString().split(",").last);
  List<int> _selectedFile = _bytesData;

  request.files.add(http.MultipartFile.fromBytes('file', _selectedFile,
      contentType: new MediaType('application', 'octet-stream'),
      filename: "text_upload.txt"));

  request.send().then((response) 
    print("test");
    print(response.statusCode);
    if (response.statusCode == 200) print("Uploaded!");
  );

【讨论】:

contentType: new MediaType('application', 'octet-stream') 对我有用。非常感谢 嗨,大文件怎么样。比方说8GB。我不认为 List _selectedFile = _bytesData;在这种情况下有效。

以上是关于选择一个文件并使用 Flutter Web 通过 POST 发送的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Web:文件选择器抛出“无效参数(路径):不能为空”错误

使用 dart:HTML 库在 Flutter Web 中选择文件时如何获取 Flutter 中的文件名?

如何将 Flutter Web 应用程序嵌入网站并通过网站将数据发送到 Flutter Web 应用程序

将用户上传到 Flutter Web 的图片存储为实际的 .jpg 文件

Flutter Web - 使用电话选择图像

如何从存储中选择多个图像并在 Flutter 和 Flutter Web App 中显示? [关闭]