120

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?

6
  • 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. Commented Mar 10, 2018 at 7:09
  • 2
    Similar question answered here stackoverflow.com/questions/44841729/… Commented Jul 16, 2018 at 10:58
  • 1
    @AravindVemula I don't want to send base64 encoded bytes Commented Jul 21, 2018 at 6:06
  • this answer helped me stackoverflow.com/a/49645074/6133481 Commented Jul 24, 2018 at 7: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. Commented Jun 23, 2020 at 6:42

20 Answers 20

87

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'] = '[email protected]';
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!");
});
Sign up to request clarification or add additional context in comments.

9 Comments

The docs are wrong per this github issues
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.
Thx bro your code helped me to solve sending fields (string) in MultipartFile in Flutter
@rmtmckenzie what is the 'package' and 'build/package.tar.gz' parameters in MultipartFile.fromPath
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.
|
66

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

6 Comments

Please write here the solution instead of including a link that could be broken in the future. Thanks!
can to change image file name using DIO?
@wendu Can I know where UploadFileInfo() function come from?
@dipgirl The UploadFileInfo is deprecated, right now there is MultiPartFromFile class for to do this. Here is a sample github.com/flutterchina/dio#sending-formdata
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...
|
58

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!");
    });
  }

8 Comments

Worked like a charm. :) tnq so much :) just to add:- please add " import 'package:http_parser/http_parser.dart'; " for contentType
works for me, just changed File.fromUri("<path/to/File">) to File.fromUri(Uri.parse("<path/to/file>"))
Why the response doesn't have response.body
@BagusAjiSantoso request.send doesn't return Future<Response>, It returns Future<StreamedResponse>. See this question stackoverflow.com/questions/55520829/…
Where are you important "MediaType" from?
|
27

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);

    });

4 Comments

what do you mean by basename
import this package import 'package:path/path.dart';
hmm you know that path, async and http are extenal plugins, right?
That's very close implementation the way I do ... i also provide the contentType: type final mimeTypeData = lookupMimeType(file.path)?.split('/'); with mime package and assign like contentType: mimeTypeData != null ? MediaType(mimeTypeData[0], mimeTypeData[1]) : null,
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);

Comments

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;
    }
  }

2 Comments

how to PUT data?
What did you mean by PUT data? if you mean data by just a field then imageUploadRequest.fields['fieldName'] = 'your value';
10

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;

Comments

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');
    }

2 Comments

I get error at "MediaType". Am I missing any imports?
import 'package:http_parser/http_parser.dart'; this should solve your issue.
8

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);

Comments

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
      }

1 Comment

Improve your answer with supporting information, like explaining the code for better understanding.
3

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);
    }
}

1 Comment

can you add this method definition lookupMimeType()..
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')

Comments

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!

1 Comment

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.
2

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

Comments

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,
);

2 Comments

how about pdf file?
@H.Fa8 You need to change the media type that is compatible with the file you want to upload
2

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

Comments

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;
}

2 Comments

Map<String, dynamic> result = { HttpKeys.status: false, HttpKeys.message: ':-(', HttpKeys.data: null, HttpKeys.token: '', }; Future<Map<String, dynamic>>
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.
1
Future postData ()async{
    var request = http.MultipartRequest('POST', Uri.parse('url'));
      request.fields.addAll({
        'docType': 'Passport',
        'docCountry': 'Italy'
      });
      request.files.add(await http.MultipartFile.fromPath('documentFront', '${imagepath}'));
      request.files.add(await http.MultipartFile.fromPath('documentBack', '${imagePath}'));

      var streamedResponse = await request.send();
      var response = await http.Response.fromStream(streamedResponse);
      if (response.statusCode == 201) {
        return jsonDecode(response.body);
      }
      else {
        return jsonDecode(response.body);
      }

  }

Comments

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}',
    };
  }

Comments

-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');
  }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.