springfluttermultipartdio

flutter dio make a multipart request


I am using the following simplified code to make a multipart request with dio


  Future<void> _updateAvatar(AssetEntity entity) async {
    var file = await entity.file;
    if (file == null){
      ToastUtils.showShortError("image not found");
      return;
    }
    var cropped = await ImageCropper().cropImage(
      sourcePath: file.path,
      aspectRatioPresets: [
        CropAspectRatioPreset.square,
      ],
    );
    if (cropped == null){
      ToastUtils.showInfo("crop canceled");
      return;
    }
    var multipartFile = await ImageUtils.multipartFileFromFile(cropped);
    if (multipartFile == null){
      ToastUtils.showShortError("cannot create image file");
      return;
    }
    await UserService.updateAvatar(multipartFile, (p) {
      ToastUtils.showSuccessful("avatar is updated~");
    });
  }

  static Future<http.MultipartFile?> multipartFileFromFile(File? file) async {
    if (file == null) {
      return null;
    }
    String uri = file.path;
    int dotIndex =  uri.lastIndexOf(".");
    String filename = DateTime.now().toString() + uri.substring(dotIndex);
    http.MultipartFile mf = await http.MultipartFile.fromPath("file", file.path, filename: filename);
    return mf;
  }

  static Future<void> updateAvatar(http.MultipartFile file, Function(String) responseHandler) async {
    dio.FormData files = dio.FormData.fromMap({
      'file': file,
    });
    await HttpUtils.uploadWithDefaultClient<String?>('/service/user/current/avatar/update', files, null, (data){
      if (data == null){
        return;
      }
      String avatar = data;
      Global.user!.avatar = avatar;
      for (Function listener in avatarListeners) {
        listener(avatar);
      }
      responseHandler(avatar);
    });
  }

Future<custom.Response<Map<String, dynamic>?>> postMultipart(String url, FormData formData, [Function(int, int)? onProgress]) async {
    var dio = Dio();
    if (host != null){
      dio.options.baseUrl = host!;
    }
    dio.options.headers = {
      ...headers,
      'Cookie': 'worldstreet_at=$accessToken',
    };
    return await _handleDioRequest(dio.post(url, data: formData, onSendProgress: onProgress));
  }

However, dio keeps giving me http status code of 400. I believe there is something wrong with the request.

This is my server code using Spring Java:

@RequestMapping("/current/avatar/update")
public String updateCurrentUserAvatar(@RequestPart("file") MultipartFile file){
    Long uid = LoginUtils.getUid();
    User user = userService.selectByUid(uid);
    FileInfo fileInfo = fileService.uploadAvatar(file);
    ExceptionUtils.failIf(fileInfo == null, "upload failed");
    String avatar = fileInfo.getUrl();
    if (avatar != null){
        fileService.deleteFile(user.getAvatar());
        user.setAvatar(avatar);
    }
    userService.update(user);
    return avatar;
}

This is what my server says about the request [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present]

I am able to make the upload request using c# and postman, but flutter dio keeps telling me wrong.

I have tried changing server's @RequestPart to @RequestParam, setting ContentType to `multipart/form-data` None just still not works.

Either changing the server or the frontend code is fine for me.

Thanks in advance!


Solution

  • I found the problem!

    I am using the MultipartFile from http package not dio package. Changing to dio fixed it!