我正在尝试在 s3 presignedURL 上上传图像(在流中)。然而,它给了我 403。通过 POSTMAN 上传相同的文件可以工作,但通过改造完成时则不行。我错过了什么?
以下是我的代码:-
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream)//bitmap is the bitmap of the image
val byteArray = stream.toByteArray()
val encodedImage = Base64.encodeToString(byteArray, Base64.DEFAULT)
val requestBody : RequestBody = encodedImage.toRequestBody()// for base64 format
val url = 'https://s3.presigned_url.com'
val baseUrl = url.split(".com").toTypedArray()[0] + ".com"
var queryUrl: String? = url.split(".com").toTypedArray()[1]
val client = OkHttpClient.Builder().build()
val retrofit_image_upload: Retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
var request1 = retrofit_image_upload.create(Api::class.java)
try {
request1.upload(
url,
fileSize,//size of the image
requestBody,
).enqueue(
object : retrofit2.Callback<Void> {
override fun onResponse(call: Call<Void>, response: Response<Void>) {
println(response.code().toString())
}
override fun onFailure(call: Call<Void>, t: Throwable) {
println(t.toString())
}
}
)
} catch (e: IOException) {
e.printStackTrace()
}
上传方法如下:-
@PUT
fun upload(
@Url url: String,
@Header("content-length") contentlength: Int,
@Body image: RequestBody,
): Call<Void>
也将请求体转换为流,但结果是一样的。
我参考了以下文章,但仍然无法解决。
Android HttpURLConnection PUT 到 Amazon AWS S3 403 错误
PUT 上传文件到 AWS S3 预签名 url Retrofit2 Android
https://gutier.io/post/android-upload-file-to-aws-s3-bucket-with-retrofit2/
使用http url连接
val connection: HttpURLConnection = URL(presignedUrl).openConnection() as HttpURLConnection
connection.doOutput = true`
connection.setRequestProperty("Content-Type", "image/png")
connection.requestMethod = "PUT"
val out = DataOutputStream(connection.outputStream)
val fileBytes = file.readBytes()
out.write(fileBytes)
out.close()
if (connection.responseCode == 200){
TODO
}`
我最近遇到了类似的情况,经过一番挣扎,我找到了解决方案。如果您使用预签名 URL 以二进制形式将图像上传到 S3,则需要使用 Retrofit 传递 @Query 或 @QueryMap 中的所有查询参数。
@PUT
fun uploadFile(
@Url url: String,
@Body file: RequestBody,
@QueryMap param: Map<String, String>
): Call<Unit>
您可以使用此功能来创建QueryMap
fun String.createQueryMap(): Map<String, String> {
val queryMap = mutableMapOf<String, String>()
val parts = split("?")
if (parts.size > 1) {
val queryString = parts[1]
val queryParams = queryString.split("&")
for (queryParam in queryParams) {
val keyValue = queryParam.split("=")
if (keyValue.size == 2) {
val key = keyValue[0]
val value = keyValue[1]
queryMap[key] = value
}
}
}
return queryMap
}
让我知道您在此之后遇到任何问题