使用OkHttp上传到预先签署的S3 URL失败
当我尝试使用OkHttp 3.9.1将文件上传到Amazon S3的预签名URL时,出现SSLexception: SSLException: Write error: ssl=0xa0b73280: I/O error during system call, Connection reset by peer
这是同样的问题,在另一个SO问题,但在我的情况下,它总是失败。 我只上传大小超过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的做法有什么不同,可能会导致此SSLexception?
编辑:
这是OkHttp代码上传文件(使用默认的application/octet-stream
MIMEtypes):
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 });