Flutter DIO: upload image using binary body with Dio package
Asked Answered
S

7

10

With thwe http package I can send an image to a server by putting te binary data in the body of a post call like in the snippet of this code:

var response = await http.post('My_url', body: File(path).readAsBytesSync(),  headers: {
                    'apikey': 'myAPIKEY',
                    'Content-Type': 'image/*', // set content-length
                  });

I can't do the same thing by using Dio, I don't know how to put directly the binary data in the body (like i can do it with postman)

postman

Splitlevel answered 30/6, 2020 at 1:11 Comment(3)
have you found a solution?Horrid
Not yet, i would try to write to Dio developers.Splitlevel
Have you found a solution yet? Stuck at the same problem,Nason
A
15

I also faced the same you have. In DIO you have to send the binary data through streams. Here is the example how I achieved it,

Uint8List image = File(path).readAsBytesSync();

Options options = Options(
  contentType: lookupMimeType(path),
  headers: {
    'Accept': "*/*",
    'Content-Length': image.length,
    'Connection': 'keep-alive',
    'User-Agent': 'ClinicPlush'
  }
);

Response response = await dio.put(
  url,
  data: Stream.fromIterable(image.map((e) => [e])),
  options: options
);
Amon answered 28/1, 2021 at 9:34 Comment(2)
I will just add that to use the lookupMimeType() method you need to import the mime package: import 'package:mime/mime.dart';Stomatology
Worked for me but when I try to upload image which 24 MB it crashed probably due to Stream.fromIterable(image.map((e) => [e]))Maida
N
6

Just putting my solution if someone stumbles upon the same issue.

I had to upload the file at a signed google storage URL. API required to insert the file binary data in the body of the PUT request. Couldn't implement using the DIO plugin, I resolved the issue using the DART HTTP package, Below is a sample code.

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

await http.put(
  Uri.parse(uploadURL),
  headers: {
    'Content-Type': mimeType,
    'Accept': "*/*",
    'Content-Length': File(filePath).lengthSync().toString(),
    'Connection': 'keep-alive',
  },
  body: File(filePath).readAsBytesSync(),
);
Nason answered 30/10, 2020 at 7:26 Comment(2)
This saved the day! Not sure why DIO struggles to handle this, but good ol fashion dart http handles it. DIO did do the upload but only pushed the byte array, which was not helpful. Thanks!Cycad
I tried for days with dio and failed. Using HTTP solved the problem, thank you <3Lumbye
M
5

Anirban Das solutions is working however when I tried to upload 24MB photo file it crashed probably due to

Stream.fromIterable(image.map((e) => [e]))

So instead I tried to directly read file as stream file.OpenRead() => which returns Strea<List<in>>>

accendent or not but upload speed also increased (maybe becase when you map e => [e] it were slowing down sending data) but who know maybe I'm wrong

So final code for me is

Uint8List image = File(path).readAsBytesSync();

Options options = Options(
  contentType: lookupMimeType(path),
  headers: {
    'Accept': "*/*",
    'Content-Length': image.length,
    'Connection': 'keep-alive',
    'User-Agent': 'ClinicPlush'
  }
);

Response response = await dio.put(
  url,
  data: file.openRead(), <--- change here
  options: options
);
Maida answered 17/11, 2021 at 8:40 Comment(0)
O
3

I have declared a FormData object named 'data' and have a map of image with key as filename and value as filepath. 'image' is the key defined on the server side.

 data.files.add(MapEntry(
    'image',
      await MultipartFile.fromFile(image.values.first, filename: "${image.values.first.split("/").last}")
                                ));
Obtrude answered 30/6, 2020 at 5:28 Comment(0)
S
1

I kept getting http 403 when using dio package to upload binary data to google storage api. I was able to fix this using :

      Response responseGoogleStorage = await dio.put(
      googleStorage.url,
      data: File(_imageFile.path).readAsBytesSync(),
      options: Options(
        headers: {
          'Content-Type': contentType,
          'Accept': "*/*",
          'Content-Length': File(_imageFile.path).lengthSync().toString(),
          'Connection': 'keep-alive',
        },
      ),
    );
Sybilla answered 12/1, 2021 at 13:27 Comment(1)
Thanks a lot! this saved the day! Not really wanted to use good old http just for one request! Same scenario as you, uploading data to Google Storage and getting a 403 response.Kwiatkowski
O
1

After combining multiple answers, this solution finally worked for me:

var len = await image.length();
var response = await dio.put(url,
    data: image.openRead(),
    options: Options(headers: {
      Headers.contentLengthHeader: len,
      "Content-Type": "image/jpg",
    } // set content-length
));
Ornithology answered 5/2, 2023 at 18:1 Comment(0)
T
1

As some people previously commented, dio really is converting to string, and in my case, that was the problem.

As a solution I've replaced the whole request body by uint8List and it worked.

final uint8List = file.readAsBytesSync();
await _dio.put(
  url,
  options: Options(
    requestEncoder: (final request, final options) {
      return uint8List;
    },
    headers: {
      Headers.contentLengthHeader: '$length',
      Headers.contentTypeHeader: contentType,
    },
  ),
  data: uint8List,
  onSendProgress: (final count, final total) => onProgress(count / total),
);
Tiros answered 28/4, 2023 at 8:55 Comment(1)
Thanks pal, it worked, the requestEncoder did itClimax

© 2022 - 2025 — McMap. All rights reserved.