How to upload images and file to a server in Flutter?
Asked Answered
S

20

113

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?

Siamang answered 6/3, 2018 at 7:9 Comment(6)
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.Siamang
Similar question answered here #44842229Faience
@AravindVemula I don't want to send base64 encoded bytesSiamang
this answer helped me https://mcmap.net/q/112422/-how-to-upload-images-to-server-in-flutterSiamang
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.Sechrist
Here is mysolution which handled for all the media types based on filePathCountless
U
82

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!");
});
Unfleshly answered 20/3, 2018 at 7:11 Comment(9)
The docs are wrong per this github issuesMaryrosemarys
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.Unfleshly
Thx bro your code helped me to solve sending fields (string) in MultipartFile in FlutterMattern
@Unfleshly what is the 'package' and 'build/package.tar.gz' parameters in MultipartFile.fromPathFranciscafranciscan
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.Unfleshly
Hi, if I want to upload video, I can use this method also?Analogical
@Analogical 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 fileUnfleshly
How can I convert back to imageThedrick
Here is mysolution which handled for all the media types based on filePathCountless
O
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

Onerous answered 4/5, 2018 at 9:34 Comment(5)
Please write here the solution instead of including a link that could be broken in the future. Thanks!Tyrocidine
can to change image file name using DIO?Vesica
@Onerous Can I know where UploadFileInfo() function come from?Analogical
@Analogical The UploadFileInfo is deprecated, right now there is MultiPartFromFile class for to do this. Here is a sample github.com/flutterchina/dio#sending-formdataPearlstein
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...Amy
P
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!");
    });
  }
Petro answered 13/8, 2018 at 0:39 Comment(8)
Worked like a charm. :) tnq so much :) just to add:- please add " import 'package:http_parser/http_parser.dart'; " for contentTypeScorpius
works for me, just changed File.fromUri("<path/to/File">) to File.fromUri(Uri.parse("<path/to/file>"))Oldest
Why the response doesn't have response.bodyPapa
@BagusAjiSantoso request.send doesn't return Future<Response>, It returns Future<StreamedResponse>. See this question #55521329Robbegrillet
Where are you important "MediaType" from?Dall
I'm struggling to put my image file path. Image I'm getting form imagePicker File.fromUri("<path/to/file>" [ #69205107 ]Lillith
@OliverDixon import package http_parserDayledaylight
Is there any particular reason for not just using http.MultipartFile.fromPath( 'file', filePath); and going through fromBytes(readAsBytes())? Thank you.Lonni
S
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);

    });
Supination answered 7/3, 2020 at 6:17 Comment(6)
what do you mean by basenameNarcoma
import this package import 'package:path/path.dart';Supination
hmm you know that path, async and http are extenal plugins, right?Snick
Amazing work brother. The problem which didn't solve in 3 days you solved it in 30 minutes.Receptor
I am glad it worked for you @Laraib.SheikhSupination
it works, I appreciate you providing a response message.Villanueva
M
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);
Monkhood answered 2/10, 2020 at 12:38 Comment(0)
D
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;
    }
  }
Didactic answered 19/7, 2021 at 10:27 Comment(2)
how to PUT data?Burrton
What did you mean by PUT data? if you mean data by just a field then imageUploadRequest.fields['fieldName'] = 'your value';Didactic
P
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;
Perspicacity answered 20/5, 2020 at 22:28 Comment(0)
R
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');
    }
Reconvert answered 10/5, 2020 at 3:18 Comment(2)
I get error at "MediaType". Am I missing any imports?Edi
import 'package:http_parser/http_parser.dart'; this should solve your issue.Olsewski
W
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);
Woald answered 21/1, 2021 at 13:56 Comment(0)
C
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
      }
Copperplate answered 16/9, 2021 at 4:33 Comment(1)
Improve your answer with supporting information, like explaining the code for better understanding.Phalanger
S
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);
    }
}
Staw answered 13/4, 2020 at 10:51 Comment(1)
can you add this method definition lookupMimeType()..Terwilliger
J
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')

Janijania answered 3/4, 2021 at 17:10 Comment(0)
H
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!

Hogshead answered 9/1, 2022 at 22:39 Comment(1)
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.Fluoridation
A
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

Absa answered 17/6, 2020 at 20:20 Comment(0)
I
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,
);
Innervate answered 22/11, 2022 at 2:19 Comment(2)
how about pdf file?Tit
@Tit You need to change the media type that is compatible with the file you want to uploadInnervate
L
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;
}
Lei answered 16/5, 2022 at 7:41 Comment(2)
Map<String, dynamic> result = { HttpKeys.status: false, HttpKeys.message: ':-(', HttpKeys.data: null, HttpKeys.token: '', }; Future<Map<String, dynamic>>Lei
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.Fluoridation
M
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
Maupassant answered 14/4, 2023 at 8:26 Comment(0)
S
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);
      }

  }
Satchel answered 4/9, 2023 at 9:48 Comment(0)
S
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}',
    };
  }
Stinkpot answered 21/2, 2023 at 2:48 Comment(0)
O
-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');
  }
}
Ovoid answered 2/6, 2020 at 12:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.