Retrofit2 无法使用 Multipart 或 RequestBody 上传图像

Retrofit2 failed to upload image with Multipart or RequestBody

我已经尝试了几种方法来为服务器发送图像,就像在 Postman 中一样

但 none 确实成功了。

第一种方式通过@Multipart:

interface Api {   
@Multipart
@POST("/upload-file")
fun uploadFile(@Part("file") file: RequestBody,
               @Part("data") id: FileUploadModel): Single<Response<AdvertisementResponse>>
}

存储库中的方法 class:

 override fun uploadFile(
    id: FileUploadModel,
    filePath: String
): Single<Response<AdvertisementResponse>> {

    val requestFile = RequestBody.create(MediaType.parse("image/*"), file)

    return api.uploadFile(requestFile, id)
}

第二种使用RequestBody的方式:

 @POST("/upload-file")
 fun uploadFile(@Body requestBody: RequestBody): Single<Response<AdvertisementResponse>>

存储库中的方法 class:

override fun uploadFile(
    id: FileUploadModel,
    filePath: String
): Single<Response<AdvertisementResponse>> {

    val file = File(filePath)
    val builder = MultipartBody.Builder()
    builder.setType(MultipartBody.FORM)

    val requestFile = RequestBody.create(MediaType.parse("image/*"), file)

    builder.addFormDataPart("file", file.name, requestFile)
    builder.addFormDataPart("data", id.toJson())

    return api.uploadFile(builder.build())
}

通过MultipartBody.Part的第三种方式:

@Multipart
@POST("/upload-file")
fun uploadFile(@Part("file") file: MultipartBody.Part,
               @Part("data") id: FileUploadModel): Single<Response<AdvertisementResponse>>

存储库中的方法 class:

 override fun uploadFile(
    id: FileUploadModel,
    filePath: String
): Single<Response<AdvertisementResponse>> {

    val file = File(filePath)
    val requestFile = RequestBody.create(MediaType.parse("image/*"), file)
    val multipartFile = MultipartBody.Part.createFormData("file", file.name, requestFile)

    return api.uploadFile(multipartFile, id)
}

日志显示 POST 上传文件请求未完成:

2020-08-15 13:52:35.828 D/OkHttpInterceptor: --> POST http://####/advertisement 2020-08-15 13:52:35.829 D/OkHttpInterceptor: Content-Type: application/json 2020-08-15 13:52:35.829 D/OkHttpInterceptor: Content-Length: 233 2020-08-15 13:52:35.829 D/OkHttpInterceptor: {"businessName":"mgskhsgmhz","email":"test@email.com","emirates":"Abu Dhabi","image":"/storage/emulated/0/Pictures/1768cbfe-e5eb-4ae0-b642-be2733cfedbe969168674235591475.jpg","note":"","ownerName":"mhzm","phone":"1111","website":""} 2020-08-15 13:52:35.829 D/OkHttpInterceptor: --> END POST (233-byte body) 2020-08-15 13:52:36.233 D/OkHttpInterceptor: <-- 201 Created http://####/advertisement (403ms) 2020-08-15 13:52:36.233 D/OkHttpInterceptor: X-Powered-By: Express 2020-08-15 13:52:36.234 D/OkHttpInterceptor: Access-Control-Allow-Origin: * 2020-08-15 13:52:36.234 D/OkHttpInterceptor: Content-Type: application/json; charset=utf-8 2020-08-15 13:52:36.234 D/OkHttpInterceptor: Content-Length: 303 2020-08-15 13:52:36.235 D/OkHttpInterceptor: ETag: W/"12f-hAPhr6BG9nzrhDMQ2eMpt2ypCAk" 2020-08-15 13:52:36.235 D/OkHttpInterceptor: Date: Sat, 15 Aug 2020 10:52:37 GMT 2020-08-15 13:52:36.235 D/OkHttpInterceptor: Connection: keep-alive 2020-08-15 13:52:36.237 D/OkHttpInterceptor: {"Error":{},"Data":{"_id":"5f37be7552e7000012180324","businessName":"mgskhsgmhz","email":"test@email.com","emirates":"Abu Dhabi","image":"/storage/emulated/0/Pictures/1768cbfe-e5eb-4ae0-b642-be2733cfedbe969168674235591475.jpg","note":"","ownerName":"mhzm","phone":"1111","website":""},"HasError":false} 2020-08-15 13:52:36.237 D/OkHttpInterceptor: <-- END HTTP (303-byte body) 2020-08-15 13:52:36.244 D/123: sent: 5f37be7552e7000012180324 2020-08-15 13:52:36.278 D/OkHttpInterceptor: --> POST http://####/upload-file 2020-08-15 13:52:36.278 D/OkHttpInterceptor: Content-Type: multipart/form-data; boundary=894cbe1b-0fc4-47c6-849d-3764193c214f 2020-08-15 13:52:36.279 D/OkHttpInterceptor: Content-Length: 104305

不知为何Retrofit无法完成此类请求

感谢任何建议

干杯

问题是由于无法从磁盘读取文件造成的。

使用 Android sdk 29 将 android:requestLegacyExternalStorage="true" 添加到 Android 清单对我有用。

<application
android:name=".MyApplication"
android:requestLegacyExternalStorage="true" ...

除了添加 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 权限。