file-uploadflutter-webmultipartfile

Couldn't upload image to server in Flutter Web


I've created a flutter application for android and web. In Flutter web, I tried to upload image to server just like it works with firebase. But it is not working somehow. I've seen some solutions for this task. But I wonder, what is actually wrong with my code.

final url = Uri.parse('$apiHeader/poststore');
String token = await getUserToken();

Map<String, String> headers = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
  'Authorization': 'Bearer $token'
};

var request = http.MultipartRequest("POST", url);


request.headers.addAll(headers);

request.fields['category_id'] = model.categoryId;
request.fields['title'] = model.title;


//I want to know about this section of the code, how can i make it work
if (kIsWeb) {
  final fileBytes =
      await model.image.readAsBytes(); // convert into bytes

  var multipartFile = http.MultipartFile.fromBytes(
      'fileName[]', fileBytes); // add bytes to multipart

  request.files.add(multipartFile);
} else {
  var multipartFile = await http.MultipartFile.fromPath(
      'fileName[]', model.image.path);

  request.files.add(multipartFile);
}

var response = await request.send();


Solution

  • Your code seems to be perfect for uploading files to Firebase Storage in flutter web. But it will never work with APIs. You simply need to change your method of file selection. Instead of image_picker or file_picker. You can use the universal_html package or you could simply import the html.dart file which comes with flutter SDK.

    First of all import the package

    import 'package:universal_html/html.dart' as html;
    

    now use this method to pick the file in web

    Future<Either<String, html.File>> pickWebFile() async {
    final Completer<Either<String, html.File>> completer = Completer();
    
    html.FileUploadInputElement uploadInput = html.FileUploadInputElement();
    uploadInput.accept = '.xlsx, .pdf'; // specify file extensions you want to pick
    uploadInput.multiple = false;
    uploadInput.click();
    
    uploadInput.onChange.listen((e) {
      final files = uploadInput.files;
      if (files != null && files.isNotEmpty) {
        final file = files.first;
        completer.complete(Right(file));
      } else {
        completer.complete(const Left('No file selected'));
      }
    });
    
    uploadInput.onError.listen((e) {
      completer.complete(const Left('Error selecting file'));
    });
    
    return completer.future;
    

    }

    once you have picked the file(s), then call this method to to upload file(s) using the API call

    Future<Either<String, String>> uploadFileToServer(html.File file) async {
    final Completer<Either<String, String>> completer = Completer();
    
    try {
      User? user = FirebaseAuth.instance.currentUser;
      if (user == null) {
        return const Left('User is not logged in');
      }
    
      String? token = await user.getIdToken(true);
      Uri url = Uri.parse(ApiEndpoints.uploadDoc);
    
      final reader = html.FileReader();
      reader.readAsArrayBuffer(file);
    
      reader.onLoadEnd.listen((event) async {
        try {
          final fileBytes = reader.result as Uint8List;
    
          var request = http.MultipartRequest('POST', url)
            ..headers['Authorization'] = 'Bearer $token'
            ..headers['Content-Type'] = 'multipart/form-data'
            ..files.add(http.MultipartFile.fromBytes('file', fileBytes, filename: file.name));
    
          var response = await request.send();
          var responseBody = await http.Response.fromStream(response);
    
          if (response.statusCode == 200) {
            debugPrint('File uploaded successfully: ${responseBody.body}');
            completer.complete(const Right('File Uploaded Successfully!'));
          } else {
            debugPrint('Failed to upload file: ${response.statusCode}');
            debugPrint('Response: ${responseBody.body}');
            completer.complete(Left('Error: ${responseBody.body}'));
          }
        } catch (e) {
          debugPrint('Error uploading file: $e');
          completer.complete(Left('Error Uploading File: $e'));
        }
      });
    
      reader.onError.listen((event) {
        debugPrint('Error reading file: ${event.toString()}');
        completer.complete(Left('Error: ${event.toString()}'));
      });
    
    } catch (e) {
      debugPrint('Error uploading file: $e');
      completer.complete(Left('Error Uploading File: $e'));
    }
    
    return completer.future;
    

    }

    please note you need to import these packages to use this code:

    import 'dart:convert';
    import 'package:dartz/dartz.dart';
    import 'dart:io' as io;
    import 'package:path/path.dart' as path;
    import 'package:intl/intl.dart';
    import 'package:http/http.dart' as http;
    import 'package:universal_html/html.dart' as html;