将文件上传到AWS S3预签名URL Retrofit2 Android

7
我有一个来自AWS S3的预签名上传URL,用于上传视频文件。在Postman上测试,视频成功上传。然而,在retrofit中实现时,返回了403错误。我不能使用多部分上传来完成这个任务。
服务调用:
@Headers("Content-Type: video/mp4")
    @PUT
    fun uploadTaskAWS(@Url awsUrl: String, @Body filePart: RequestBody): Call<ResponseBody>

上传:

            val file = File(task.file_path)
            val requestFile = RequestBody.create(MediaType.parse("video/mp4"), file)
            val response = awsTaskUploadService.uploadTaskAWS(task.upload_url, requestFile)

我已确保URL正确,也添加了内容类型头部,Postman截图已附上。出现403禁止错误。 Postman截图 我找到了相关的问题,但仍然遇到403错误。 使用Retrofit2将文件上传到AWS S3预签名URL 有什么建议吗?
3个回答

8
解决方案是包含multipart并期望单个响应而不是调用:
  @Multipart
    @PUT
    fun uploadAsset(
        @Header(CONTENT_TYPE) contentType: String,
        @Url uploadUrl: String,
        @Part file: MultipartBody.Part
    ): Single<ResponseBody>

在这里,contentType是传递进来的。

val requestFile = RequestBody.create(MediaType.parse(contentType), file)
val body = MultipartBody.Part.createFormData(mediaType, task.file_name, requestFile)
assetService.uploadAsset(contentType, task.upload_url, body)

5
对于其他寻找解决方法的人,我遇到了同样的问题,建议的方法现在已经过时了,而且Android现在使用内容提供程序,使得访问底层文件变得棘手。如果您有兴趣,我在这里记录了我的解决方案:链接 - zzantares
完美的解决方案。请跟随@ZzAntáres提供的链接。 - Lokesh Desai
谢谢@ZzAntáres。 - Victor Ude
谢谢你,@ZzAntáres。你救了我的一天。 - hassan mirza
单个未定义。应该从哪里添加? - KIRAN K J

1

403错误意味着服务器知道你是谁,但没有执行所需操作的权限。

如果预签名URL正确生成,您应该能够在不进行任何身份验证的情况下上传。

您可以检查Postman是否默认添加了任何AWS身份验证请求。

如果上传到仅使用版本4的区域,则还需要显式设置协议版本来签署请求。


1
协议版本是什么意思? - charitha amarasinghe

0

我尝试了很多次使用Retrofit,但都没有成功,最终我使用HttpURLConnection实现了它。

 class UploadImageUsingPreSignedUrl(
    var bitmap: Bitmap?,
    var signedURL: String,
    var imageUploadCallback: ImageUploadCallback
) : AsyncTask<Void?, Void?, Int>() {
    override fun doInBackground(vararg p0: Void?): Int {
        var respCode = -1
        try {
            val url = URL(signedURL)
            val connection = url.openConnection() as HttpURLConnection
            connection.requestMethod = "PUT"
            connection.doOutput = true
            connection.setRequestProperty("Content-Type", "image/png") // your content type
            val outputStream = connection.outputStream
            bitmap?.compress(Bitmap.CompressFormat.PNG, 70, outputStream)
            outputStream.close()
            respCode = connection.responseCode
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return respCode
    }

    override fun onPostExecute(responseCode: Int) {
        super.onPostExecute(responseCode)
        imageUploadCallback.imageUpload(responseCode == 200)
    }
}

ImageUploadCallback在哪里? - undefined
@aliozkara,ImageUploadCallback回调包含一个方法(imageUpload),该方法的参数为bool类型。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接