问题
Problem Statement
Hi, basically, what I want is to send a file through a POST to a python server-side Flask API.
The goal is to provide the user with a file picker interface, and after him/her choosing the desired .txt
file, send it through Dio using a POST request.
A button (Widget) should call this uploadFile()
function and everything should be handle by it
Code
Here is my current code:
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'}));
}
Trial Outcome
The problem here is that FileReader does not have a readAsBytes
method, therefore I can't send the file as a Multipart file using the fromBytes method.
The only methods FileReader has are: readAsDataUrl
, readAsArrayBuffer
and readAsText
I don't want to read the .txt body to send it, I want to send the actual file.
Other tries
- I have also tried using file_picker but it seems that it does not support Flutter Web
Reference Links
My try is based on: Is there any plugin or way to upload file to server using flutter web?
and some others that I could not find again.
React Inspiration
The way I've managed to do it in React was:
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
});
Cry
Please, help? I am stuck on it for more than 4 days and could not yet figure out how to solve this in Flutter Web...
回答1:
Managed to do it:
As described in this blog post:
1. I've made FileReader read as DataUrl
reader.readAsDataUrl(file);
2. Treat data, transforming it into Byte
Uint8List _bytesData =
Base64Decoder().convert(file.toString().split(",").last);
List<int> _selectedFile = _bytesData;
3. To read it, use Multipart.readFromBytes()
:
file = http.MultipartFile.fromBytes('file', _selectedFile,
contentType: new MediaType('application', 'octet-stream'),
filename: "text_upload.txt")
4. To send it, use 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!");
});
Final Code Looks Like This
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!");
});
}
来源:https://stackoverflow.com/questions/59761947/choose-a-file-and-send-through-post-with-flutter-web