当我尝试使用OkHttp 3.9.1将文件上传到Amazon S3的预签名网址时,我收到了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()
这是生成预签名上传网址的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
});
答案 0 :(得分:0)
这似乎适用于改造库:
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
}