【问题标题】:Upload to pre-signed S3 URL fails with OkHttp使用 OkHttp 上传到预签名的 S3 URL 失败
【发布时间】:2018-07-08 08:00:17
【问题描述】:

当我尝试使用 OkHttp 3.9.1 将文件上传到 Amazon S3 的预签名 URL 时遇到 SSL 异常:SSLException: Write error: ssl=0xa0b73280: I/O error during system call, Connection reset by peer

这与another SO question 中的问题相同,但在我的情况下它总是失败。我只上传大小超过 1MiB 的文件,我没有尝试过小文件。

正如我在该问题的回答中提到的,切换到 Java 的 HttpURLConnection 解决了问题并且上传完美。

这是我的 RequestBody 实现(在 Kotlin 中)从 Android 的 Uri 上传文件,我确实使用 OkHttp 的 .put() 方法:

class UriRequestBody(private val file: Uri, private val contentResolver: ContentResolver, private val mediaType: MediaType = MediaType.parse("application/octet-stream")!!): RequestBody() {
    override fun contentLength(): Long = -1L

    override fun contentType(): MediaType? = mediaType

    override fun writeTo(sink: BufferedSink) {
        Okio.source((contentResolver.openInputStream(file))).use {
            sink.writeAll(it)
        }
    }
}

这是我的HttpURLConnection 实现:

private fun uploadFileRaw(file: Uri, uploadUrl: String, contentResolver: ContentResolver) : Int {
    val url = URL(uploadUrl)
    val connection = url.openConnection() as HttpURLConnection
    connection.doOutput = true
    connection.requestMethod = "PUT"
    val out = connection.outputStream

    contentResolver.openInputStream(file).use {
        it.copyTo(out)
    }

    out.close()
    return connection.responseCode
}

OkHttp 的不同之处在于它会导致 SSL 异常吗?

编辑:

这里是上传文件的 OkHttp 代码(使用默认的application/octet-stream mime 类型):

val s3UploadClient = OkHttpClient().newBuilder()
    .connectTimeout(30_000L, TimeUnit.MILLISECONDS)
    .readTimeout(30_000L, TimeUnit.MILLISECONDS)
    .writeTimeout(60_000L, TimeUnit.MILLISECONDS)
    .retryOnConnectionFailure(true)
    .build()

val body: RequestBody = UriRequestBody(file, contentResolver)
val request = Request.Builder()
        .url(uploadUrl)
        .put(body)
        .build()

s3UploadClient.newCall(request).execute()

这是生成预签名上传 URL 的 JavaScript 服务器代码:

const s3 = new aws.S3({
    region: 'us-west-2',
     signatureVersion: 'v4'
});
const signedUrlExpireSeconds = 60 * 5;

const signedUrl = s3.getSignedUrl('putObject', {
    Bucket: config.bucket.name,
    Key: `${fileName}`,
    Expires: signedUrlExpireSeconds
});

【问题讨论】:

    标签: android amazon-web-services amazon-s3 okhttp okhttp3


    【解决方案1】:

    这似乎适用于改造库:

    fun uploadImage(imagePath: String, directUrl: String): Boolean {
        Log.d(TAG, "Image: ${imagePath}, Url: $directUrl")
        val request = Request.Builder()
                .url(directUrl)
                .put(RequestBody.create(null, File(imagePath)))
                .build()
        val response = WebClient.getOkHttpClient().newCall(request).execute()
        return response.isSuccessful
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-26
      • 1970-01-01
      • 2016-10-12
      • 2020-09-30
      • 2019-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多