当前位置: 首页 > 知识库问答 >
问题:

已生成AWS签名Url不支持Android Retrofit2上传视频调用(mp4)

吕子真
2023-03-14

我有一个来自AWS的签名网址。

我使用下面的代码上传我的mp4文件。

 val retrofit = Retrofit.Builder()
            .baseUrl("https://www.DUMMEY.com/") // THIS BASE URL AUTOMATICALLY REPLACE ONCE RETROFIT INTERFACE BODY ATTACH WITH @URL
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()

        val videoInterface = retrofit.create(
            FileUploadService::class.java
        )

        var apiResponse: Call<Void>
        val requestBody = activity.contentResolver.readAsRequestBody(fileUri)
        apiResponse = videoInterface.upload(
            "video/mp4",
            "Android-OS",
            signedurl,
            requestBody
        )
        apiResponse.enqueue(object : Callback<Void> {
            override fun onResponse(
                call: Call<Void>,
                response: Response<Void>
            ) {
                Log.d("SUCCESS", "=========API RESPONE SUCCESS=========" + apiResponse)
            }

            override fun onFailure(call: Call<Void>, t: Throwable) {
                Log.e("FAILED", "=========API RESPONE FAILED=========" + apiResponse)
            }

        })
    }.start()



fun ContentResolver.readAsRequestBody(uri: Uri): RequestBody =
    object : RequestBody() {
        override fun contentType(): MediaType? =
            this@readAsRequestBody.getType(uri)?.toMediaTypeOrNull()

        override fun writeTo(sink: BufferedSink) {
            this@readAsRequestBody.openInputStream(uri)?.source()?.use(sink::writeAll)
        }

        override fun contentLength(): Long =
            this@readAsRequestBody.query(uri, null, null, null, null)?.use { cursor ->
                val sizeColumnIndex: Int = cursor.getColumnIndex(SIZE)
                cursor.moveToFirst()
                cursor.getLong(sizeColumnIndex)
            } ?: super.contentLength()
    }

interface FileUploadService {
@PUT
fun upload(
    @Header("Content-Type") contentType: String?,
    @Header("User-Agent") userAgent: String?,
    @Url signingUrl: String?,
    @Body file: RequestBody
): Call<Void>

}

但我还是没能成功。

我在运行代码时一直收到“javax.net.ssl.SSLException:写入错误:ssl=0xe8abb908:系统调用期间的I/O错误,断管”这个错误。(但我觉得这不仅是一个SSLException,而且我的代码也有一个巨大的错误)

根据邮递员的输出,它应该用200 OK来响应“1”。

我也尝试使用“Multipart.Part”来表示我的文件,也使用此代码

   val file = File(fileUri!!.path!!)
   val requestBody = InputStreamRequestBody(activity.contentResolver, fileUri)
   val filePart = MultipartBody.Part.createFormData("file", file.name, requestBody)

接口是..

 @Multipart
@PUT
fun uploadHope(
    @Header("Content-Type") contentType: String?,
    @Header("User-Agent") userAgent: String?,
    @Url signingUrl: String?,
    @Part file: MultipartBody.Part
): Call<Void>

出现了同样的错误。

我关注这个博客作为帮助。

请帮我把“上传成功”放在这上面。

共有1个答案

梁丘凯定
2023-03-14

我做了一个大调查,但失败了。Retrofit2 似乎不支持此 AWS 签名 Url 上传。但是我成功地采用了“HttpUrlConnection”的方式。通常我们使用。

 private static final int BUFFER_SIZE = 1024 * 1024 * 10;



 fun uploadFile(signedurl: String? = null, filePath: String? = null) {
    Thread {
        var serverResponseCode = -1
        try {
            var url: URL? = null
            url = URL(signedurl)
            val connection = url.openConnection() as HttpURLConnection
            connection.doOutput = true
            connection.requestMethod = "PUT"
            connection.setRequestProperty("Content-Type", " ") // Very important ! It won't work without adding this!
            var dos: DataOutputStream? = null
            var bytesRead: Int
            var bytesAvailable: Int
            var bufferSize: Int
            var buffer: ByteArray
            val sourceFile: File = File(filePath)
            try {
                FileInputStream(sourceFile).use { fileInputStream ->
                    dos = DataOutputStream(connection.outputStream)
                    bytesAvailable = fileInputStream.available()
                    bufferSize = Math.min(
                        bytesAvailable,
                        BUFFER_SIZE
                    )
                    buffer = ByteArray(bufferSize)
                    bytesRead = fileInputStream.read(buffer, 0, bufferSize)
                    while (bytesRead > 0) {
                        dos!!.write(buffer, 0, bufferSize)
                        bytesAvailable = fileInputStream.available()
                        bufferSize = Math.min(
                            bytesAvailable,
                            BUFFER_SIZE
                        )
                        bytesRead = fileInputStream.read(buffer, 0, bufferSize)
                    }
                }
            } catch (e: Exception) {
                Log.e("Log", "error " + e)
            } finally {
                // close the streams
                if (dos != null) {
                    dos!!.flush() //send any left data
                    dos!!.close()
                }
            }
            serverResponseCode = connection.responseCode
            Log.e("response", "response code " + serverResponseCode)
        } catch (e: Exception) {
            Log.e("Log", "error " + e)
        }
    }.start()
}

如果你遵循这种方法,请突出显示这些行,

var url: URL? = null
            url = URL(signedurl)
            val connection = url.openConnection() as HttpURLConnection


connection.setRequestProperty("Content-Type", " ") // Very important ! It won't work without adding this!

注意:-在某些情况下,此服务可能会响应200(正常),但内容可能不会上载。因为AWS S3 bucket只接受文件对象,它不会检查可用内容,也不会回复200。因此,如果发生此错误,请联系服务器,首先查看错误是什么。

如果有人找到了一种方法,通过2上传到AWS。请在这里回答。

 类似资料:
  • 我已经使用我的后端代码生成了预先设计的URL,然后使用该URL上传了一个在会话期间录制的视频。我在前端使用下面的代码(React JS)来上传视频,预检似乎失败了,因为403禁止,post请求失败了,因为cors错误。请查看以下详细信息: 使用的代码: 控制台错误:访问“获取时间”https://xxxxxxxxxx“起源”http://localhost:5000'已被CORS策略阻止:对飞行前

  • 我知道水桶是存在的。当我通过AWS Web GUI导航到此项目并双击它时,它将打开带有URL的对象,并且运行良好: 所以我认为我在使用SDK时肯定做错了什么。

  • 有没有办法让预签名的aws上传URL在出现错误时返回json响应,而不是xml响应。 目前,如果url过期,它会返回如下内容。 如果这是json响应就好了。

  • 我按照https://docs.aws.amazon.com/amazons3/latest/dev/shareObjectPresignedurlJavasdk.html中的示例创建预签名的s3 url(v4),当我试图访问签名的url时,会出现Access Denied错误 下面是代码段 签名格式似乎是正确的,我不确定是否遗漏了其他一些s3客户端配置。由于我没有得到签名不匹配错误或无效的url

  • 如果你想把自己的资源发放给第三方用户访问,但是又不想开放Bucket的读权限,可以通过生成预签名URL的形式提供给用户一个临时的访问URL。在生成URL时,你可以指定URL过期的时间,从而限制用户长时间访问。 生成一个预签名的URL 如下代码: String bucketName = "your-bucket-name"; String key = "your-object-key"; // 设

  • 如果你想把自己的资源发放给第三方用户访问,但是又不想开放Bucket的读权限,可以通过生成预签名URL的形式提供给用户一个临时的访问URL。在生成URL时,你可以指定URL过期的时间,从而限制用户长时间访问。 生成预签名URL来获取Object <?php $url = $client->generatePresignedUrl(array( 'Bucket' => 'your-buck