Android 网络之 Volley+OkHttp+Https

原创 2016年05月31日 19:29:01
    Volley 已经发布很长时间了, 也已被广泛应用, 相关教程到处都是. 本文只说两个值得注意的地方.

本文讲解部分比较少, 请参阅提供的相关链接. 完整的实现代码在 Github dodocat/AndroidNetworkDemo 可能看起来比这里更清晰.


使用 OkHttp 作为传输层的实现.

Volley 默认根据 Android 系统版本使用不同的 Http 传输协议实现.
在 Android 2.3以下使用 ApacheHttpStack 作为传输协议, 在 3.0 及以下使用 HttpURLConnection 作为传输层协议 (感谢评论中指正的朋友).

OkHttp 相较于其它的实现有以下的优点.

  • 支持SPDY,允许连接同一主机的所有请求分享一个socket。
  • 如果SPDY不可用,会使用连接池减少请求延迟。
  • 使用GZIP压缩下载内容,且压缩操作对用户是透明的。
  • 利用响应缓存来避免重复的网络请求。
  • 当网络出现问题的时候,OKHttp会依然有效,它将从常见的连接问题当中恢复。
  • 如果你的服务端有多个IP地址,当第一个地址连接失败时,OKHttp会尝试连接其他的地址,这对IPV4和IPV6以及寄宿在多个数据中心的服务而言,是非常有必要的。

因此使用 OkHttp 作为替代是好的选择.

  1. 首先用 OkHttp 实现一个新的 HurlStack 用于构建 Volley 的 requestQueue.

    public class OkHttpStack extends HurlStack {
    
     private OkHttpClient okHttpClient;
    
     /**
      * Create a OkHttpStack with default OkHttpClient.
      */
     public OkHttpStack() {
         this(new OkHttpClient());
     }
    
     /**
      * Create a OkHttpStack with a custom OkHttpClient
      * @param okHttpClient Custom OkHttpClient, NonNull
      */
     public OkHttpStack(OkHttpClient okHttpClient) {
         this.okHttpClient = okHttpClient;
     }
    
     @Override
     protected HttpURLConnection createConnection(URL url) throws IOException {
         OkUrlFactory okUrlFactory = new OkUrlFactory(okHttpClient);
         return okUrlFactory.open(url);
     }
    }
  2. 然后使用 OkHttpStack 创建新的 Volley requestQueue.

    requestQueue = Volley.newRequestQueue(getContext(), new OkHttpStack());
    requestQueue.start();

    这样就行了.

使用 Https

    作为一个有节操的开发者应该使用 Https 来保护用户的数据, Android 开发者网站上文章Security with HTTPS and SSL做了详尽的阐述.OkHttp 自身是支持 Https 的. 参考文档 OkHttp Https, 直接使用上面的 OkHttpStack 就可以了, 但是如果遇到服务器开发哥哥使用了自签名的证书(不要问我为什么要用自签名的), 就无法正常访问了.

    网上有很多文章给出的方案是提供一个什么事情都不做的TrustManager 跳过 SSL 的验证, 这样做很容受到攻击, Https 也就形同虚设了.

我采用的方案是将自签名的证书打包入 APK 加入信任.

好处:

  • 应用难以逆向, 应用不再依赖系统的 trust store, 使得 Charles 抓包等工具失效. 要分析应用 API 必须反编译 APK.
  • 不用额外购买证书, 省钱....

缺点:

  • 证书部署灵活性降低, 一旦变更证书必须升级程序.

实现步骤

以最著名的自签名网站12306为例说明

  1. 导出证书

     echo | openssl s_client -connect kyfw.12306.cn:443 2>&1 |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > kyfw.12306.cn.pem
  2. 将证书转为 bks 格式
    下载最新的bcprov-jdk, 执行下面的命令. storepass 是导出密钥文件的密码.

    keytool -importcert -v \
     -trustcacerts \
     -alias 0 \
     -file <(openssl x509 -in kyfw.12306.cn.pem) \
     -keystore $CERTSTORE -storetype BKS \
     -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider \
     -providerpath ./bcprov-jdk16-1.46.jar \
     -storepass asdfqaz
  3. 将导出的 kyfw.bks 文件放入 res/raw 文件夹下.

  4. 创建 SelfSignSslOkHttpStack

    /**
    * A HttpStack implement witch can verify specified self-signed certification.
    */
    public class SelfSignSslOkHttpStack extends HurlStack {
    
     private OkHttpClient okHttpClient;
    
     private Map<String, SSLSocketFactory> socketFactoryMap;
    
     /**
      * Create a OkHttpStack with default OkHttpClient.
      */
     public SelfSignSslOkHttpStack(Map<String, SSLSocketFactory> factoryMap) {
         this(new OkHttpClient(), factoryMap);
     }
    
     /**
      * Create a OkHttpStack with a custom OkHttpClient
      * @param okHttpClient Custom OkHttpClient, NonNull
      */
     public SelfSignSslOkHttpStack(OkHttpClient okHttpClient, Map<String, SSLSocketFactory> factoryMap) {
         this.okHttpClient = okHttpClient;
         this.socketFactoryMap = factoryMap;
     }
    
     @Override
     protected HttpURLConnection createConnection(URL url) throws IOException {
         if ("https".equals(url.getProtocol()) && socketFactoryMap.containsKey(url.getHost())) {
             HttpsURLConnection connection = (HttpsURLConnection) new OkUrlFactory(okHttpClient).open(url);
             connection.setSSLSocketFactory(socketFactoryMap.get(url.getHost()));
             return connection;
         } else {
             return  new OkUrlFactory(okHttpClient).open(url);
         }
     }
    }
  5. 然后用 SelfSignSslOkHttpStack 创建 Volley 的 RequestQueue.

     String[] hosts = {"kyfw.12306.cn"};
     int[] certRes = {R.raw.kyfw};
     String[] certPass = {"asdfqaz"};
     socketFactoryMap = new Hashtable<>(hosts.length);
    
     for (int i = 0; i < certRes.length; i++) {
         int res = certRes[i];
         String password = certPass[i];
         SSLSocketFactory sslSocketFactory = createSSLSocketFactory(context, res, password);
         socketFactoryMap.put(hosts[i], sslSocketFactory);
     }
    
     HurlStack stack = new SelfSignSslOkHttpStack(socketFactoryMap);
    
     requestQueue = Volley.newRequestQueue(context, stack);
     requestQueue.start();
  6. 我们来试一试, 用上一步穿件的 RequestQueue 替换掉原来的, 然后发请求试试.

         StringRequest request = new StringRequest(
                 Request.Method.GET,
                 "https://kyfw.12306.cn/otn/",
                 new Response.Listener<String>() {
                     @Override
                     public void onResponse(String response) {
                         responseContentTextView.setText(response);
                     }
                 },
                 new Response.ErrorListener() {
                     @Override
                     public void onErrorResponse(VolleyError error) {
                         responseContentTextView.setText(error.toString());
                     }
                 });
         RequestManager.getInstance(this).addRequest(request, this);

Android 网络--Volley+OkHttp+Https

Volley 已经发布很长时间了, 也已被广泛应用, 相关教程到处都是. 本文只说两个值得注意的地方. 本文讲解部分比较少, 请参阅提供的相关链接. 完整的实现代码在 Github dodocat/...
  • LANGXINLEN
  • LANGXINLEN
  • 2016年02月26日 17:31
  • 923

Android 网络: Volley+OkHttp+Https

使用 OkHttp 作为传输层的实现. Volley 默认根据 Android 系统版本使用不同的 Http 传输协议实现.  在 Android 3.0 以上 Volley 使用 Apach...
  • qlwm2016
  • qlwm2016
  • 2016年04月06日 00:40
  • 303

Android 网络--我是怎么做的: Volley+OkHttp+Https

转载自 http://www.chinaz.com/web/2015/0731/428907.shtml
  • u010384128
  • u010384128
  • 2015年08月24日 15:01
  • 683

Android 面试题总结之Android 基础(四)

Android 面试题总结之Android 基础Service(四) 在上一章节Android 面试题总结之Android 基础Broadcast Receiver(三) 我们讲了Broadcas...
  • vfush
  • vfush
  • 2016年05月26日 16:13
  • 8024

Android网络编程基础(一) - 基础知识

内容介绍:Android网络编程基础 博客地址:http://blog.csdn.net/kevindgk 版权声明:本文为原创文章,未经允许不得转载 联系方式:815852777...
  • KevinDGK
  • KevinDGK
  • 2016年08月16日 17:45
  • 2295

android存储之网络存储和数据库存储

昨天说老师说了android的网络存储,对协议有了一个更深的理解。 数据上传到网络,尽管 b/s 和c/s的架构不一样,但是它们还是能上传数据到网络,因为都遵循协议的规范,c/s存储数据到网络,思想...
  • Watering_sea
  • Watering_sea
  • 2015年07月09日 10:37
  • 811

Android访问本机ip

Android模拟器(simulator)把它自己作为了localhost,也就是说,代码中使用localhost或者127.0.0.1来访问,都是访问模拟器自己!这是不行的!         如果你...
  • zhangvalue
  • zhangvalue
  • 2016年01月09日 22:26
  • 3675

android源码分析之网络更新时间

android网络更新时间 android时间的更新方式,一般有moderm和网络更新两种,MTK在此基础上,添加了GPS的方式。现在分析的是网络更新时间的方式 从网络更新只能更新时间但是无法改变时区...
  • u013377887
  • u013377887
  • 2016年12月18日 15:58
  • 1115

Android5.0网络之策略路由应用场景

策略路由的应用场景
  • javon_hzw
  • javon_hzw
  • 2015年06月24日 17:04
  • 1424

Android 各大网络请求库的比较及实战

自己学习android也有一段时间了,在实际开发中,频繁的接触网络请求,而网络请求的方式很多,最常见的那么几个也就那么几个。本篇文章对常见的网络请求库进行一个总结。HttpUrlConnection最...
  • sbsujjbcy
  • sbsujjbcy
  • 2015年05月11日 09:30
  • 17207
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android 网络之 Volley+OkHttp+Https
举报原因:
原因补充:

(最多只允许输入30个字)