83

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?

Paresh Mangukiya
  • 37,512
  • 17
  • 201
  • 182
Mneckoee
  • 2,422
  • 5
  • 18
  • 31
  • 1
    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
  • 1
    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
  • @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

16 Answers16

63

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
  • 15,734
  • 6
  • 54
  • 57
rmtmckenzie
  • 32,848
  • 8
  • 97
  • 90
  • 1
    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 – Pritish 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
57

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,047
  • 7
  • 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
  • 2
    @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
44

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,275
  • 2
  • 22
  • 30
Robbie
  • 1,072
  • 11
  • 8
21

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
  • 9,144
  • 3
  • 37
  • 51
14

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
  • 141
  • 1
  • 2
8

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
  • 613
  • 10
  • 11
7

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

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
  • 3,763
  • 2
  • 32
  • 35
6

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
  • 3,014
  • 20
  • 30
  • 4
    To increase answer quality in the future, think about adding some text for some context and your thoughts about the code provided. – Logemann Jan 21 '21 at 19:33
  • I tried this but not working file is not receiving in server final request = http.MultipartRequest( 'POST', Uri.parse('https://yurr.app/api/register-celebrity')); request.fields['title'] = title.text; request.fields['sub_title'] = subTitle.text; request.files .add(await http.MultipartFile.fromPath('profile_photo', photo.path)); request.files .add(await http.MultipartFile.fromPath('profile_video', video.path)); var response = await request.send(); var responseString = await response.stream.bytesToString(); print(responseString); – zia sultan May 04 '21 at 07:33
  • which plugin are you using? – SilenceCodder May 22 '21 at 00:24
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
  • 331
  • 1
  • 3
  • 13
3

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
  • 129
  • 3
  • 2
    Improve your answer with supporting information, like explaining the code for better understanding. – pmadhu Sep 16 '21 at 11:56
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,326
  • 13
  • 22
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
  • 3,525
  • 1
  • 39
  • 32
1

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
  • 11
  • 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
0
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;
}
  • 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

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
  • 34,285
  • 10
  • 136
  • 109