问题
I'm unable to upload files using the Dio
plugin and I can not figure out where's the problem. In Laravel the request is always empty.
What have I done so far:
- Double check if the file path really exists using
existsSync()
function - Changed the
Content-Type
toapplication/x-www-form-urlencoded
- Validated if the file is actually being uploaded - seems yes (?)
This is my flutter code:
File myFile = new File('/storage/emulated/0/Download/demo.docx');
FormData form = new FormData.from({
'title': 'Just testing',
'file': new UploadFileInfo(myFile, 'demo.docx')
});
Before sending through POST
i checked if the file exists and returns true
print(myFile.existsSync());
And set the Content-type
properly
Response response = await Dio().post(
myUrl,
data: form,
options: new Options(
contentType: ContentType.parse("application/x-www-form-urlencoded"),
),
);
Printing the result of the form
returns
I/flutter (27929): ----dio-boundary-0118165894
I/flutter (27929): Content-Disposition: form-data; name="title"
I/flutter (27929): ----dio-boundary-1759467036
I/flutter (27929): Content-Disposition: form-data; name="file"; filename="demo.docx"
I/flutter (27929): Content-Type: application/octet-stream
Which I believe indicates that the file is being uploaded.
Now in laravel whenever i output the content received it always comes null the key file
, but the key title
comes with data.
The code print_r(json_encode($request->all()))
retrieves
{"title":"Just testing","file":{}}
The same goes for print_r(json_encode($request->file('file')))
.
What am i missing?
回答1:
Solved.
This took me a while to figure it out, but i end up realizing there's two problems with this approach:
- Laravel
$request
is empty, but$_FILES
is not - Sending multiple files can not be sent using arrays as the documentation tells
So, in order to achieve my goal which allows the user to select multiple files dynamically and upload them at the same time, here's the logic behind:
Flutter
The form must be created without setting the files right away:
FormData form = new FormData.from(
{
'title': 'Just testing',
});
Since the function .from
is a Map<String, dynamic>
values can be added after.
/*
* files = List<String> containing all the file paths
*
* It will end up like this:
* file_1 => $_FILES
* file_2 => $_FILES
* file_3 => $_FILES
*/
for (int i = 0; i < files.length; i++) {
form.add('file_' + i.toString(),
new UploadFileInfo(new File(files[i]), files[i].toString()));
}
There is no need to set up a different Content-Type
, therefore this is enough:
Response response = await Dio().post(myUrl, data: form);
Laravel / PHP
Forget about accessing the file
through $request->file()
and instead use the old school approach.
$totalFiles = count($_FILES);
for ($i = 0; $i < $totalFiles; $i++)
{
$file = $_FILES['file_' . $i];
// handle the file normally ...
$fileName = basename($file['name']);
$fileInfo = pathinfo($file);
$fileExtension = $fileInfo['extension'];
move_uploaded_file($file['tmp_name'], $path);
}
回答2:
I know this is an old post but this may help someone. this solution works for me, upload multi-file to server use Flutter Dio library and Laravel as backend. correct me if I did it wrong.
Flutter
BaseOptions _dioOption({@required String token}) {
BaseOptions options = new BaseOptions(baseUrl: baseUrl, headers: {
Headers.acceptHeader: Headers.jsonContentType,
Headers.contentTypeHeader: Headers.jsonContentType,
"Authorization": "Bearer $token"
});
return options;
}
dioPostProduct( {@required ProductToUpload productToUpload,
@required String url, String token}) async {
//productToUpload.images is a List<File>
List<Object> filesData = new List<Object>();
for (final file in productToUpload.images) {
filesData.add(MultipartFile.fromFileSync(file.path,
filename: file.path.split('/').last));
}
FormData data = FormData.fromMap({
"subcategory_id": productToUpload.subcategory_id,
"name": productToUpload.name,
"detail": productToUpload.detail,
"price": productToUpload.price,
"condition_id": productToUpload.condition_id,
"images": filesData,
});
Dio dio = new Dio(_dioOption(token: token));
Response response;
response = await dio.post(url, data: data);
if (response.statusCode == 200) {
print(response.data);
}
}
Laravel
For php resize image I use library intervention$images = Collection::wrap(request()->file('images'));
$directory = '/product_images'; //make sure directory is exist
foreach ($images as $image) {
$basename = Str::random();
$original = $basename . '.' . $image->getClientOriginalExtension();
$thumbnail = $basename . '_thumb.' . $image->getClientOriginalExtension();
Image::make($image)
->fit(400, 400)
->save(public_path($directory . '/' . $thumbnail));
$image->move(public_path($directory), $original);
}
来源:https://stackoverflow.com/questions/55478345/flutter-file-upload-with-dio-empty-in-laravel