使用客户端证书和 Android 的 HttpsURLConnection 通过 SSL 上传文件
我正在尝试将文件上传到受 SSL 保护且需要客户端证书(由内部 CA 签名)的 Web 服务。与Web服务的通信运行良好(下载文件,查询,运行命令和执行各种POST按预期工作),除了上传文件。
上传文件时,我得到一个SSLException(javax.net.ssl.SSLException),上面写着“写入错误:ssl=0x5fe209c0:系统调用期间的I / O错误,对等体重置连接”。
我已经创建了一个重复的服务器,并删除了SSL和客户端证书要求,并尝试通过“vanilla”HTTP上传,并且它工作得很好。
我尝试过使用setFixedLengthStreamingMode(int)和setChunkedStreamingMode(int),但没有成功。使用它们时,将从方法引发异常,并且当不使用其中任何一个时,从对 的调用中引发相同的异常。write
getResponseCode()
我在服务器的.EventVwr
我们的另一个客户端(iOS客户端)能够在那里上传文件,所以它一定是我做的事情 - 但我不知道是什么。
我不确定如何进一步调试此问题。
请帮忙。
编辑 1
我们做了很多调试工作,发现:
- 小文件按预期上传(44kb 是成功上传的最大文件的大小,上传时间约为 1200 毫秒)。
- 46kb 文件上传失败。失败需要大约 2 分钟 (134120ms)。
编辑 2
在你将在评论中读到的内容之后,现在我让小提琴手玩得很好(感谢这个问题)。Fiddler拿到了文件,但没有成功发送。请求(原始)如下所示:
POST https://192.168.2.2/rest/transfer/strong/Upload/Full?Path=%5C20140807_113255_20.jpg&Root=2 HTTP/1.1
SessionToken: 1234 // We use this for session management
FileMetadata: {"FileSize":"1315496","FileName":"GrumpyCat.jpg"}
Connection: Keep-Alive
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.1; GT-N7100 Build/JRO03C)
Host: 192.168.2.2
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Content-Length: 1315496
;odiao;awriorijgoeijoeirj;oedfrvgerg... // The image
小提琴手的回应(也是RAW)是:
HTTP/1.1 504 Fiddler - Send Failure
Date: Wed, 20 Aug 2014 17:40:29 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Timestamp: 20:40:29.420
[Fiddler] ResendRequest() failed: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host. < An existing connection was forcibly closed by the remote host
此外,我们还添加了 WCF 的“消息日志记录”和详细的“跟踪”。MessageLogging 不显示任何消息提示(可能在转换为消息之前已丢弃),但跟踪显示如下:
现在,在你说“啊,这是一个服务器问题”之前,请记住,44kb文件成功上传,我们的iOS应用程序也能够成功上传文件。
这是来自客户端获取的异常的调用堆栈:
E/RestClientUploader(3196): javax.net.ssl.SSLException: Write error: ssl=0x5d94b8b0: I/O error during system call, Connection reset by peer
E/RestClientUploader(3196): at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(Native Method)
E/RestClientUploader(3196): at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:693)
E/RestClientUploader(3196): at java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:231)
E/RestClientUploader(3196): at libcore.net.http.ChunkedOutputStream.writeBufferedChunkToSocket(ChunkedOutputStream.java:129)
E/RestClientUploader(3196): at libcore.net.http.ChunkedOutputStream.write(ChunkedOutputStream.java:77)
E/RestClientUploader(3196): at java.io.DataOutputStream.write(DataOutputStream.java:98)
E/RestClientUploader(3196): at com.varonis.datanywhere.communication.RestClientUploader.uploadFileToServer(RestClientUploader.java:151)
E/RestClientUploader(3196): at com.varonis.datanywhere.communication.RestClientUploader.uploadFullFile(RestClientUploader.java:67)
E/RestClientUploader(3196): at com.varonis.datanywhere.communication.services.FileUploadService.doUpload(FileUploadService.java:128)
E/RestClientUploader(3196): at com.varonis.datanywhere.communication.services.FileUploadService.onHandleIntent(FileUploadService.java:98)
E/RestClientUploader(3196): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
E/RestClientUploader(3196): at android.os.Handler.dispatchMessage(Handler.java:99)
E/RestClientUploader(3196): at android.os.Looper.loop(Looper.java:137)
E/RestClientUploader(3196): at android.os.HandlerThread.run(HandlerThread.java:60)