【发布时间】: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