题外话:今天偶尔来逛逛,发现我真是懒到家了。居然有半年前的留言我都没有来看过,真对不起留言的同学,希望他的问题已经解决了。

这两三天一直被亚马逊S3上传文件的问题困扰着,直到昨天晚上终于搞定了,工作群里一片欢腾,从客户端到服务器数位工程师卡在这个问题上抓耳挠腮了好几天,终于解决了,这就是所谓“光明总出现在最黑暗的时刻”吧,嘿嘿,非常开心,程序员真是容易满足啊。

途中搜索了很多互联上的方案,最终在stackoverflow的一个帖子里找到有价值的参考。而我们国内的站点上关于这方面的信息非常少,所以我来写这个随笔,希望为大家增加一点参考吧。

------------------------------------------------------------正式开始的分割线----------------------------------------------------------------------------

一开始我们的代码是这样,上传一个测试的mp4,我们的需求是文件size不超过10M:

     File file = new File(Environment.getExternalStorageDirectory().getPath() + "/0.mp4");

     if(!file.exists())
return;
if(!file.isFile())
return;
try {
URL url = new URL("https://secv.s3.amazonaws.com/familytest10099/DFG092833/2016/01/27/10-38-07/0.mp4?AWSAccessKeyId=AKIAIGMMMZARXIK3ZDBA&Expires=1453948689&Signature=uJvHirNhOlCuB5z20NPkYc73qV8%3D");//从自家server签出的S3 地址
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(connection.getOutputStream());
FileInputStream fileInputStream = new FileInputStream(file);// 读取文件的数据。
byte[] bufer = new byte[1024];
int len = 0, i = 0;
while ((len = fileInputStream.read(bufer)) != -1) {
bufferedOutputStream.write(bufer, 0, len);
} bufferedOutputStream.flush();
bufferedOutputStream.close(); fileInputStream.close(); int responseCode = connection.getResponseCode();
Log.d("s3_ssltest","Service returned response code " + responseCode);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

运行结果抛出异常:

javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x54b61708: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x52732cfc:0x00000000)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:448)
at com.android.okhttp.Connection.upgradeToTls(Connection.java:146)
at com.android.okhttp.Connection.connect(Connection.java:107)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:296)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:503)
at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:136)
at com.spde.switchbox.manager.secu.SecuThread.a(Unknown Source)
at com.spde.switchbox.manager.secu.SecuThread.run(Unknown Source)
Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x54b61708: Failure in SSL library, usually a protocol error
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0x52732cfc:0x00000000)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
... 11 more

出错原因是亚马逊s3 服务器端禁用了SSLv3,解决方法是自己extends一个SSLSocketFactory把SSLv3从默认的protocol中remove掉。重写的SSLSocketFactory见附件NoSSLv3Factory.java。

在创建connection之前先调用:

HttpsURLConnection.setDefaultSSLSocketFactory(new NoSSLv3Factory());

这样修改之后SSL的问题解决了,但又抛出一个异常

javax.net.ssl.SSLException: Write error: ssl=0x5ab6f5f8: I/O error during system call, Connection reset by peer
at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_write(Native Method)
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream.write(OpenSSLSocketImpl.java:693)
at java.io.ByteArrayOutputStream.writeTo(ByteArrayOutputStream.java:231)
at libcore.net.http.RetryableOutputStream.writeToSocket(RetryableOutputStream.java:70)
at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:806)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:274)
at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:486)
at libcore.net.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:134)
at com.example.test.MainActivity$SSLTestRunnable.run(MainActivity.java:73)
at java.lang.Thread.run(Thread.java:856)

原因是http header中没有指定content-type,传输格式是stream

connection.setRequestProperty("Content-Type", "application/octet-stream");

这个异常也解决了。访问成功,但是返回403 Forbidden,网上搜到很多解释说是客户端的时区或者系统时间不对,因为S3上签出的url是有expire date的。但我们出问题的原因是因为服务器签出这个url的时候没有指定Content-type , 又是Content-type的问题,修改签出地址的代码如下:

public static String createUploadUrl(String bucket, String objKey, Date expire){
    String url = s3Client.generatePresignedUrl(new GeneratePresignedUrlRequest(bucket, objKey).
                withMethod(HttpMethod.PUT).
                withContentType("application/octet-stream").
               withExpiration(expire)
            ).toString();
    return url;
}

ok,这次终于收到回复200 ok了,视频也上传成功。

困扰三天的问题就这样解决了。总结一下:一个复杂迷茫各种想不通的问题,最终解决的时候往往修改不了几行代码。

额外的说明:我们出问题的平台android版本是4.4.3,openSSL lib的版本是1.0.1e。网上搜集到的信息,SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure 这种问题通常出现在Android 4.x上。

最后是 NoSSLv3Factory.java 的源码

 

Amazon S3 上传文件 SSL23_GET_SERVER_HELLO握手错误的更多相关文章

  1. 解决wordpress上传文件出现http错误问题

    解决wordpress上传文件出现http错误问题 问题现象 今天上传约1.4m大小的gif文件到wordpress的媒体库时失败,提示http错误. 原因 由于之前一直上传图片都是可以的,所以推测最 ...

  2. idea 内置tomcat jersey 跨服务器 上传文件报400错误

    报错内容 com.sun.jersey.api.client.UniformInterfaceException: PUT http://.jpg returned a response status ...

  3. FTP上传文件提示550错误原因分析。

    今天测试FTP上传文件功能,同样的代码从自己的Demo移到正式的代码中,不能实现功能,并报 Stream rs = ftp.GetRequestStream()提示远程服务器返回错误: (550) 文 ...

  4. HipChat上传文件报未知错误解决方案

    前言 HipChat是Atlassian公司的一款团队协作即时通讯工具,服务端为Linux(官方给的服务端就是一个虚拟机),在Windows.Linux.Android.IOS.Mac等平台都有客户端 ...

  5. PHP上传文件详解 错误提示

    首先在php.ini里配置上载文件.有以下几个重要的配置单: 选项 默认值 说明 post_max_size 8M 控制以后的POST请求的最大规模.必须大于upload_max_filesize选项 ...

  6. php上传文件时出现错误:failed to open stream: Permission denied

    尝试使用php写了一段小的上传程序,但是在使用的时候,在上传文件时出现这个错误,由于之前在写程序要读文件,曾经出现过这个问题,当时是因为要读的文件的权限不够,于是使用chmod 775 1.txt把文 ...

  7. 上传文件 nginx 413错误

    nginx : 413 Request Entity Too Large 上传文件过程发生413 Request Entity Too Large错误,翻译为请求实体过大,断定为nginx限制了请求体 ...

  8. SharePoint REST 上传文件请求403错误

    最近,需要在SharePoint上传文件到文档库,但是,上传的过程报错了. 错误代码 { "error": { "code": "-213057525 ...

  9. 最近上传图片上传文件报413错误及仅Https下报413问题,IIS高版本的配置方案及Web.config配置全解

    IIS文件上传大小限制30M,C盘中有的IIS_schema.xml文件 C:\Windows\System32\inetsrv\config\schema\ 但是考虑到安全等问题,而且这个文件默认是 ...

随机推荐

  1. 更改JENKINS主目录

    在部署时,发现直接启动WAR包没办法改主目录,而此主目录空间太小, 唯有安装TOMCAT之后进行更改... 参考文档: 工作中,由于Jenkins默认的主目录空间太小,导致需要将Jenkins默认的主 ...

  2. Swift与Objective-C中的闭包

    Swift Code: func makeIncrementor(forIncrement amount: Int) -> (() -> Int,() -> Int) { func ...

  3. 使用SparseArray代替HashMap

    HashMap是java里比较常用的一个集合类,我比较习惯用来缓存一些处理后的结果.最近在做一个Android项目,在代码中定义这样一个变量,实例化时,Eclipse却给出了一个 performanc ...

  4. applicationDefaultJvmArgs:

    server.context-path=/HelloMultiServlet server.port=8080 applicationDefaultJvmArgs: [ "-agentlib ...

  5. JavaScript数学函数的操作

    <script> var a=3.14; var a1=Math.ceil(a);//大于当前小数的最小整数; alert(a1); var a2=Math.floor(a);//小于当前 ...

  6. ☀【单位】REM

    CSS3的REM设置字体大小 支持的浏览器还是蛮多的,比如:Mozilla Firefox 3.6+.Apple Safari 5+.Google Chrome.IE9+和Opera11+.只是可怜的 ...

  7. tomcat6 配置SSI 支持.shtml文件

    一.修改tomcat-6.0.36\conf\server.xml 文件: 把文件里 ssi 相关的 servlet .servlet-mapping .filter .filter-mapping注 ...

  8. 【转】Xcode7.1环境下上架iOS App到AppStore 流程 (Part 一)

    原文网址:http://www.cnblogs.com/ChinaKingKong/p/4957682.html 前言部分 之前App要上架遇到些问题到网上搜上架教程发现都是一些老的版本的教程 ,目前 ...

  9. C# Read/Write another Process' Memory ZZ

    Today's tutorial is about...processes' memory! In this article I'll show you how to read/write a pro ...

  10. 机器更换登录密码重启,然后SQL Server登录不了

    解决方法: