102

I use a web service for image processing , it works well in Postman:

postman screenshot

Now I want to make http request in flutter with Dart:

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

static ocr(File image) async {
    var url = '${API_URL}ocr';
    var bytes = image.readAsBytesSync();

    var response = await http.post(
        url,
        headers:{ "Content-Type":"multipart/form-data" } ,
        body: { "lang":"fas" , "image":bytes},
        encoding: Encoding.getByName("utf-8")
    );

    return response.body;

  }

but I don't know how to upload the image file, in above code I get exception: Bad state: Cannot set the body fields of a Request with content-type "multipart/form-data".
How should I write the body of request?

Mneckoee
  • 2,802
  • 6
  • 23
  • 34
  • 2
    for a workaround: I ask my server guys to change server api to accept base64 encoded image instead. so I put the `base64` encoded image as a string in body with content type of header equal to `application/x-www-form-urlencoded` and it works. – Mneckoee Mar 10 '18 at 07:09
  • 2
    Similar question answered here https://stackoverflow.com/questions/44841729/how-to-upload-image-in-flutter/51322060#51322060 – Aravind Vemula Jul 16 '18 at 10:58
  • 1
    @AravindVemula I don't want to send base64 encoded bytes – Mneckoee Jul 21 '18 at 06:06
  • this answer helped me https://stackoverflow.com/a/49645074/6133481 – Mneckoee Jul 24 '18 at 07:15
  • Have you tried with content-type "application/octet-stream". I always avoid "multipart/form-data" wherever I can. The best designed file-upload APIs accept "application/octet-stream" in the POST body, and any parameters are in the URI. – Kind Contributor Jun 23 '20 at 06:42
  • Here is my[solution](https://stackoverflow.com/a/74255358/2462531) which handled for all the media types based on filePath – Shailendra Madda Oct 30 '22 at 17:49

19 Answers19

74

Your workaround should work; many servers will accept application/x-www-form-urlencoded as an alternative (although data is encoded moderately inefficiently).

However, it is possible to use dart:http to do this. Instead of using http.post, you'll want to use a http.MultipartFile object.

From the dart documentation:

var request = new http.MultipartRequest("POST", url);
request.fields['user'] = 'someone@somewhere.com';
request.files.add(http.MultipartFile.fromPath(
    'package',
    'build/package.tar.gz',
    contentType: new MediaType('application', 'x-tar'),
));
request.send().then((response) {
  if (response.statusCode == 200) print("Uploaded!");
});
Spatz
  • 18,640
  • 7
  • 62
  • 66
rmtmckenzie
  • 37,718
  • 9
  • 112
  • 99
  • 2
    The docs are wrong per [this github issues](https://github.com/dart-lang/http/issues/140) – Kiana May 07 '18 at 21:49
  • Thanks @Kiana, I didn't notice that. It's fixed now. Although the `master` of dart.http is much different than the currently released 0.11.3+16, so I would expect this to eventually become incorrect. – rmtmckenzie May 07 '18 at 22:03
  • Thx bro your code helped me to solve sending fields (string) in MultipartFile in Flutter – Shashank Pujari May 02 '19 at 06:42
  • @rmtmckenzie what is the 'package' and 'build/package.tar.gz' parameters in MultipartFile.fromPath – BraveEvidence May 30 '19 at 12:07
  • 1
    Package is the name of the field (if it was a form on the web it'd be the name of the input), and build/package.tar.gz is the path. That example was really more specific to a server though; you could use one of MultipartFile's other constructors like .fromBytes or the one that uses a stream instead. – rmtmckenzie May 30 '19 at 14:32
  • Hi, if I want to upload video, I can use this method also? – dipgirl Mar 25 '20 at 06:17
  • @dipgirl As long as your server accepts and knows what the data you're sending it (and you should set the MediaType to the right thing), you can send anything. The example in the code isn't even sending an image but rather a tar file – rmtmckenzie Mar 25 '20 at 14:35
  • How can I convert back to image – User Feb 22 '22 at 05:41
  • Here is my[solution](https://stackoverflow.com/a/74255358/2462531) which handled for all the media types based on filePath – Shailendra Madda Oct 30 '22 at 17:49
62

I'd like to recommend dio package to you , dio is a powerful Http client for Dart/Flutter, which supports Interceptors, FormData, Request Cancellation, File Downloading, Timeout etc.

dio is very easy to use, in this case you can:

Sending FormData:

FormData formData = new FormData.from({
   "name": "wendux",
   "file1": new UploadFileInfo(new File("./upload.jpg"), "upload1.jpg")
});
response = await dio.post("/info", data: formData)

More details please refer to dio

wendu
  • 1,187
  • 9
  • 9
  • 11
    Please write here the solution instead of including a link that could be broken in the future. Thanks! – Ignacio Ara May 04 '18 at 09:58
  • can to change image file name using DIO? –  May 06 '19 at 11:23
  • 2
    @wendu Can I know where UploadFileInfo() function come from? – dipgirl Mar 21 '20 at 14:04
  • 3
    @dipgirl The UploadFileInfo is deprecated, right now there is MultiPartFromFile class for to do this. Here is a sample https://github.com/flutterchina/dio#sending-formdata – ugurerkan Jun 11 '20 at 05:33
  • it hard to decide on this, since while some people say Dio promisses a lot, other say it also fails a lot and witout providing meaningfull error messages... – MarcoFerreira Aug 20 '22 at 16:09
54

This can be achieved using the MultipartRequest class (https://pub.dev/documentation/http/latest/http/MultipartRequest-class.html)

Change the media type and uri as needed.

uploadFile() async {
    var postUri = Uri.parse("<APIUrl>");
    var request = new http.MultipartRequest("POST", postUri);
    request.fields['user'] = 'blah';
    request.files.add(new http.MultipartFile.fromBytes('file', await File.fromUri("<path/to/file>").readAsBytes(), contentType: new MediaType('image', 'jpeg')))

    request.send().then((response) {
      if (response.statusCode == 200) print("Uploaded!");
    });
  }
ggrana
  • 2,335
  • 2
  • 21
  • 31
Robbie
  • 1,291
  • 12
  • 10
  • 22
    Worked like a charm. :) tnq so much :) just to add:- please add " import 'package:http_parser/http_parser.dart'; " for contentType – rashmi chachan Jun 27 '19 at 16:39
  • 10
    works for me, just changed ```File.fromUri(") ``` to ```File.fromUri(Uri.parse(""))``` – yubaraj poudel Feb 13 '20 at 11:22
  • 1
    Why the response doesn't have response.body – Bagus Aji Santoso Aug 31 '20 at 18:21
  • 2
    @BagusAjiSantoso request.send doesn't return ```Future```, It returns ```Future```. See this question https://stackoverflow.com/questions/55520829/how-to-get-response-body-with-request-send-in-dart/55521892 – poring91 Jan 27 '21 at 05:55
  • 4
    Where are you important "MediaType" from? – Oliver Dixon Aug 04 '21 at 12:44
  • I'm struggling to put my image file path. Image I'm getting form imagePicker `File.fromUri(""` [ https://stackoverflow.com/questions/69204607/how-to-pass-image-file-to-the-body-of-http-request-post-in-flutter ] – Tuhin Sep 16 '21 at 16:28
  • @OliverDixon import package http_parser – vietstone Oct 17 '21 at 22:14
  • Is there any particular reason for not just using ```http.MultipartFile.fromPath( 'file', filePath); ``` and going through ```fromBytes(readAsBytes())```? Thank you. – Sina Seirafi Oct 17 '22 at 12:20
25

I found a working example without using any external plugin , this only uses

import 'package:http/http.dart' as http;
import 'dart:io';
import 'package:path/path.dart';
import 'package:async/async.dart';
import 'dart:convert';

Code

var stream =
        new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
    // get file length
    var length = await imageFile.length(); //imageFile is your image file
    Map<String, String> headers = {
      "Accept": "application/json",
      "Authorization": "Bearer " + token
    }; // ignore this headers if there is no authentication

    // string to uri
    var uri = Uri.parse(Constants.BASE_URL + "api endpoint here");

    // create multipart request
    var request = new http.MultipartRequest("POST", uri);

  // multipart that takes file
    var multipartFileSign = new http.MultipartFile('profile_pic', stream, length,
        filename: basename(imageFile.path));

    // add file to multipart
    request.files.add(multipartFileSign);

    //add headers
    request.headers.addAll(headers);

    //adding params
    request.fields['loginId'] = '12';
    request.fields['firstName'] = 'abc';
   // request.fields['lastName'] = 'efg';

    // send
    var response = await request.send();

    print(response.statusCode);

    // listen for response
    response.stream.transform(utf8.decoder).listen((value) {
      print(value);

    });
Quick learner
  • 10,632
  • 4
  • 45
  • 55
18

How to upload image file using restAPI in flutter/dart.

This work for me.

var postUri = Uri.parse("apiUrl");

http.MultipartRequest request = new http.MultipartRequest("POST", postUri);

http.MultipartFile multipartFile = await http.MultipartFile.fromPath(
    'file', filePath); 

request.files.add(multipartFile);

http.StreamedResponse response = await request.send();


print(response.statusCode);
Aida Bico
  • 181
  • 1
  • 2
11

Updated 2021 way:

using flutter http and mime

import 'package:mime/mime.dart';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';
import 'dart:io';


  Future<dynamic> multipartImageUpload(String baseUrl, String api, File image) async {
    var uri = Uri.parse(baseUrl + api);
    final mimeTypeData =
        lookupMimeType(image.path, headerBytes: [0xFF, 0xD8]).split('/');

    // Intilize the multipart request
    final imageUploadRequest = http.MultipartRequest('PUT', uri);

    // Attach the file in the request
    final file = await http.MultipartFile.fromPath('image', image.path,
        contentType: MediaType(mimeTypeData[0], mimeTypeData[1]));
    imageUploadRequest.files.add(file);

    // add headers if needed
    //imageUploadRequest.headers.addAll(<some-headers>);

    try {
      final streamedResponse = await imageUploadRequest.send();
      final response = await http.Response.fromStream(streamedResponse);
      return response;
    } catch (e) {
      print(e);
      return null;
    }
  }
Charitha Goonewardena
  • 4,418
  • 2
  • 36
  • 38
9

Use MultipartRequest class. How to upload image file using restAPI in flutter/dart

  void uploadImage1(File _image) async {

    // open a byteStream
    var stream = new http.ByteStream(DelegatingStream.typed(_image.openRead()));
    // get file length
    var length = await _image.length();

    // string to uri
    var uri = Uri.parse("enter here upload URL");

    // create multipart request
    var request = new http.MultipartRequest("POST", uri);

    // if you need more parameters to parse, add those like this. i added "user_id". here this "user_id" is a key of the API request
    request.fields["user_id"] = "text";

    // multipart that takes file.. here this "image_file" is a key of the API request
    var multipartFile = new http.MultipartFile('image_file', stream, length, filename: basename(_image.path));

    // add file to multipart
    request.files.add(multipartFile);

    // send request to upload image
    await request.send().then((response) async {
      // listen for response
      response.stream.transform(utf8.decoder).listen((value) {
        print(value);
      });

    }).catchError((e) {
      print(e);
    });
  }

name spaces:

import 'package:path/path.dart';
import 'package:async/async.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
Supun Dewapriya
  • 695
  • 11
  • 13
8

UPLOAD IMAGE TO SERVER WITH FORM DATA

To upload image to server you need a dio library.

Features:

  1. Authorization (adding token)
  2. Adding extra field like: username, etc
  3. Adding Image to upload

Code example:

import 'package:dio/dio.dart' as dio;
import 'dart:convert';

    try {
      ///[1] CREATING INSTANCE
      var dioRequest = dio.Dio();
      dioRequest.options.baseUrl = '<YOUR-URL>';

      //[2] ADDING TOKEN
      dioRequest.options.headers = {
        'Authorization': '<IF-YOU-NEED-ADD-TOKEN-HERE>',
        'Content-Type': 'application/x-www-form-urlencoded'
      };

      //[3] ADDING EXTRA INFO
      var formData =
          new dio.FormData.fromMap({'<SOME-EXTRA-FIELD>': 'username-forexample'});

      //[4] ADD IMAGE TO UPLOAD
      var file = await dio.MultipartFile.fromFile(image.path,
            filename: basename(image.path),
            contentType: MediaType("image", basename(image.path)));

      formData.files.add(MapEntry('photo', file));

      //[5] SEND TO SERVER
      var response = await dioRequest.post(
        url,
        data: formData,
      );
      final result = json.decode(response.toString())['result'];
    } catch (err) {
      print('ERROR  $err');
    }
7

To add a header and use http multipart with https://pub.dev/packages/multi_image_picker Plugin,

This is the code.

var request =  http.MultipartRequest(
        'POST', Uri.parse(myurl)

      );
      //Header....
      request.headers['Authorization'] ='bearer $authorizationToken';
      
       request.fields['PropertyName'] = propertyName;
    request.fields['Country'] = country.toString();
    request.fields['Description'] = des;
    request.fields['State'] = state.toString();
       request.files.add(http.MultipartFile.fromBytes(
      'ImagePaths',
      learnImage,
      filename: 'some-file-name.jpg',
  contentType: MediaType("image", "jpg"),
    )
        );
var response = await request.send();
print(response.stream);
print(response.statusCode);
final res = await http.Response.fromStream(response);
  print(res.body);

To use HTTP and https://pub.dev/packages/image_picker PLUGIN

This is the code

var request =  http.MultipartRequest(
        'POST', Uri.parse(myurl)

      );
      request.headers['Authorization'] ='bearer $authorizationToken';
       request.fields['PropertyName'] = propertyName;
    request.fields['Country'] = country.toString();
    request.fields['Description'] = des;
    request.fields['State'] = state.toString();
       request.files.add(await http.MultipartFile.fromPath(
      'ImagePaths',
      file.path
    )
        );
var response = await request.send();
    print(response.stream);
    print(response.statusCode);
    final res = await http.Response.fromStream(response);
      print(res.body);
SilenceCodder
  • 2,874
  • 24
  • 28
4

Working Code

String path = userSelectedImagePath;
    Map<String, String> data = {
      "name": firstName!,
      "email": userEmail!
    };
   

    String token = await LocaldbHelper().getToken();
    Map<String, String> headers = {
      'X-Requested-With': 'XMLHttpRequest',
      'authorization': 'Bearer $token',
    };


   var request = http.MultipartRequest(
        'POST',
        Uri.parse(ApiUrl.updateProfile),
      );
      request.fields.addAll(data);
      request.headers.addAll(headers);
      var multipartFile = await http.MultipartFile.fromPath(
          'avatar', path); //returns a Future<MultipartFile>
      request.files.add(multipartFile);
      http.StreamedResponse response = await request.send();
      final respStr = await response.stream.bytesToString();
      var jsonData = jsonDecode(respStr);
      if (response.statusCode == 200) {
        // success
      } else {
        // error
      }
Deepak Yadav
  • 227
  • 3
  • 4
  • 2
    Improve your answer with supporting information, like explaining the code for better understanding. – pmadhu Sep 16 '21 at 11:56
3

Just leaving this here, if anyone is trying to upload a pdf or any other document using MultipartRequest method.

Just add the content type as - contentType: new MediaType('application', 'pdf')

Aajinkya Singh
  • 543
  • 1
  • 6
  • 14
3

Good code with Dio and FilePicker for post file on your server. I use flutter for the web.

FilePicker Dio

  1. First you need writing Dio post method.
    Future postImportClient(PlatformFile file) async {
        try {
          var urlBase = 'your url';
          var mfile = MultipartFile.fromBytes(file.bytes!, filename: file.name);
          var formData = FormData();
          formData.files.add(MapEntry('file', mfile));
          await _dio.post(urlBase, data: formData);
        } on DioError catch (error) {
          throw Exception(error);
        }
      }
  1. Initial FilePicker and get file.
FilePickerResult? result = await FilePickerWeb.platform.pickFiles();
if (result != null) {
var file = result.files.single;
await client.postImportClient(file);
}

Good luck!

zoLikeCode
  • 31
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 10 '22 at 04:05
2

create FormData:

final formDataMap = <String, dynamic>{};
formDataMap["stringKey"] = "string";
List<MultipartFile> multipartImageList = [];
await Future.forEach(imagePaths as List<String>,(String path) async {
  final multiPartFile = await MultipartFile.fromFile(
                          path,
                          contentType: MediaType("image", "jpeg"),
                        );
  multipartImageList.add(multiPartFile);
});
formDataMap["image[]"] = multipartImageList;
final formData = FormData.fromMap(formDataMap);

With Retrofit & Dio:

@MultiPart()
@POST("{{url}}")
Future<dynamic> uploadFormData(
  @Body() FormData formData,
);
hungtrn75
  • 21
  • 3
1

With Hearder upload image

Future uploadImageMedia(File fileImage, String token) async {


  final mimeTypeData =
        lookupMimeType(fileImage.path, headerBytes: [0xFF, 0xD8]).split('/');
         final imageUploadRequest =
        http.MultipartRequest('POST', Uri.parse(mainUrlSite + "wp-json/wp/v2/media"));

    final file = await http.MultipartFile.fromPath('file', fileImage.path,
        contentType: MediaType(mimeTypeData[0], mimeTypeData[1]));

    imageUploadRequest.files.add(file);
    imageUploadRequest.headers.addAll({
      "Authorization": "Bearer " + token
    });
    try {
      final streamedResponse = await imageUploadRequest.send();

      streamedResponse.stream.transform(utf8.decoder).listen((value) {
        print(value);
        return Future.value(value);
      });
    } catch (e) {
      print(e);
    }
}
Rahman Rezaee
  • 1,943
  • 16
  • 24
1

I use Dio library with put method:

    var formData = FormData.fromMap({
      'simpleParam': 'example',
      'file': await MultipartFile.fromFile(filePath, filename: 'file.jpg')
    });

    var dio = Dio();
    dio.options.headers[HttpHeaders.authorizationHeader] = myToken;

    var response = new Response(); //Response from Dio
    response = await dio.put(myUrl + "/myApi", data: formData);

The result is in response.data

Álvaro Agüero
  • 4,494
  • 1
  • 42
  • 39
1
try {
  result[HttpKeys.status] = false;
  var request = http.MultipartRequest('POST', url);
  request.fields.addAll(body);

  if (avatar.path.isNotEmpty) {
    request.files.add(await http.MultipartFile.fromPath('uploadedImg', avatar.path));
  }

  request.headers.addAll(headers);

  http.StreamedResponse streamResponse = await request.send();

  final response = await http.Response.fromStream(streamResponse);

  if (response.statusCode == 200) {
    var resMap = jsonDecode(response.body);
    debugPrint('<==    ==>');
    // debugPrint(response.body);
    result[HttpKeys.status] = true;
    result[HttpKeys.message] = resMap[HttpKeys.message];
    result[HttpKeys.data] = resMap['data'];

    return result;
  } else {
    var resMap = jsonDecode(response.body);
    result[HttpKeys.message] = resMap[HttpKeys.message];
    return result;
  }
} catch (error) {
  result[HttpKeys.message] = error.toString();
  return result;
}
hasan_iota
  • 21
  • 1
  • Map result = { HttpKeys.status: false, HttpKeys.message: ':-(', HttpKeys.data: null, HttpKeys.token: '', }; Future> – hasan_iota May 16 '22 at 09:07
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 17 '22 at 19:28
1

Summary

I write a example using flutter to upload file with multipart/form-data format with 2 steps. Both steps contains optional package for options. The example request contains 2 fields: File for {file:slide.pdf} and Text for {owner:Gary}.

enter image description here

Stpe 1: Pick File (to bytes data)

Method 1: Use html(built-in library, web only), or universal_html

example code:

// choose one of below pacakges
import 'dart:html' as html;
// import 'package:universal_html/html.dart' as html;

Future<html.File?> pickHtmlFile() async {
  final uploadElement = html.FileUploadInputElement()
    ..multiple = false
    ..click();
  await uploadElement.onChange.first;
  return uploadElement.files?.first;
}

Future<Uint8List?> readBytes(html.File file) async {
  final reader = html.FileReader()
    ..readAsArrayBuffer(file);
  await reader.onLoadEnd.first;
  return reader.result as Uint8List?;
}


...

final htmlFile = await pickHtmlFile();
if (htmlFile == null) return;
final bytes = await readBytes(htmlFile);
if (bytes == null) return;
// htmlFile.name => file name
// bytes => byte data of the file 

...

Method 2: use file_picker (Recommand)

example code:

import 'package:file_picker/file_picker.dart';

final picked = await FilePicker.platform.pickFiles();
final platformFile = picked?.files.single;
final bytes = platformFile?.bytes;
if (platformFile == null || bytes == null) return;
// platformFile.name => file name
// bytes => byte data of the file

Step2: Upload Formdata with POST

Method1: use http (Official)

example code:

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

...

final multipartFile =
    http.MultipartFile.fromBytes('file', bytes, filename: filename);
final request = http.MultipartRequest('POST',Uri.parse('[YOUR API URL HERE]'))
  ..files.add(multipartFile)
  ..fields['owner'] = 'Gary';

final responseStream = await request.send();
final response = await http.Response.fromStream(responseStream);
// response.statusCode => 200 is OK
// response.body => response data here

Method2: use dio

example code:

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

...

final multipartFile = dio.MultipartFile.fromBytes(bytes, filename: filename);
final formData = dio.FormData.fromMap({'file': multipartFile, 'owner': 'Gary'});
final response = await dio.Dio().post('[YOUR API URL HERE]',data: formData,);
// response.statusCode => 200 is OK
// response.data => response data here
yellowgray
  • 4,006
  • 6
  • 28
0

Here is the code where I am passing Image, route which may be like '/register', and data which is Map<String, String> like data={'directory':'profile'}.

For Uploading Image to Laravel API, Authorization in header is compulsory otherwise it would return "You don't have permission to access this resource". I am passing token as EMPTY string like String token='' as I am uploading Image at user registration time

This Authorization for read and write is defined in domainurl/public/.htaccess file, you can change it

Try to understand the below code and all the issue would be resolve.


  Future uploadImage({
    required XFile file,
    required String route,
    required Map<String, String> data,
  }) async {
    String url = API_Url + route;
    final uri = Uri.parse(url);
    try {
      http.MultipartRequest request = http.MultipartRequest("POST", uri);
      http.MultipartFile multipartFile =
          await http.MultipartFile.fromPath('image', file.path);
      request.files.add(multipartFile);
      request.headers.addAll(_header());
      request.fields.addAll(data);
      var streamedResponse = await request.send();
      var response = await http.Response.fromStream(streamedResponse);
      print(jsonDecode(response.body));
      return jsonDecode(response.body);
    } catch (e) {
      return null;
    }
  }

  _header() {
    return {"Content-Type": "multipart/form-data",
      'Authorization': 'Bearer ${token}',
    };
  }
-1

With dio I do like this:

Future<void> _uploadFileAsFormData(String path) async {
  try {
    final dio = Dio();

    dio.options.headers = {
      'Content-Type': 'application/x-www-form-urlencoded'
    };

    final file =
      await MultipartFile.fromFile(path, filename: 'test_file');

    final formData = FormData.fromMap({'file': file}); // 'file' - this is an api key, can be different

    final response = await dio.put( // or dio.post
      uploadFileUrlAsString,
      data: formData,
    );
  } catch (err) {
    print('uploading error: $err');
  }
}
Andrew
  • 36,676
  • 11
  • 141
  • 113