Android OkHttp及http、https网络请求方法

       最近在搞微信支付的SDK开发,微信这个开放平台真是说不清,怎么感觉比地图和语音的SDK差的有点多,问题一大推,demo中的网络请求用的是apache的httpClient这个类来实现https请求,并且做了keystore验证,想到以前用的都是jdk自带的HttpURLConnection这个类来做网络请求,并且Android studio上大都用OkHttp了,试了一下,OkHttp确实简单又好用,而且也支持get,post带参数,Json,字节流,文件等,还添加了表单,分块等方式,在对OkHttp进一步封装后网络请求的使用甚至一行代码就可以解决,大大优化了代码效率,比如github上这个OkHttp开源框架https://github.com/hongyangAndroid/okhttp-utils,当然我们还是要通过API对OkHttp的细节掌握了。

     我们以前一般使用的HttpUrlConnection和HttpClient这两个类来封装我们的网络工具类,实现的细节就不多说了,大家都很常用,比如下面的代码实现带参数的post方式的https请求。

public static String post(String httpsUrl, String params) {
		String result = null;
		try {
			URL url = new URL(httpsUrl); // 解析httpsUrl,生成url对象
			SSLContext sslctxt = SSLContext.getInstance("TLS"); // 为请求通TLS协议,生成SSLContext对象
			// 初始化SSLContext
			sslctxt.init(null, new TrustManager[] { new MyX509TrustManager() },
					new java.security.SecureRandom());

			HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();

			conn.setSSLSocketFactory(sslctxt.getSocketFactory());
			conn.setHostnameVerifier(new MyHostnameVerifier());
			conn.setDoInput(true);
			conn.setDoOutput(true);
			conn.setRequestMethod("POST");
			conn.setUseCaches(false);
			conn.connect();

			conn.getOutputStream().write(params.getBytes());
			conn.getOutputStream().flush();
			conn.getOutputStream().close();

			int respCode = conn.getResponseCode();
			Log.d(TAG, "ResponseCode=" + respCode);
			if(respCode == 200) {
				InputStream input = conn.getInputStream();
				result = toString(input);
				input.close();
			}
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (KeyManagementException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}
   下面是微信支付demo的网络工具类,截取一段代码,getNewHttpClient里面做了keystore加载和证书的参数设置,唯一需要注意的是jar包最好用最新的,不然会报错误。
  public static byte[] httpGet(final String url) {
		if (url == null || url.length() == 0) {
			Log.d(TAG, "httpGet, url is null");
			return null;
		}

		HttpClient httpClient = getNewHttpClient();
		Log.d(TAG, "httpClient;" + httpClient);
		HttpGet httpGet = new HttpGet(url);

		try {
			HttpResponse resp = httpClient.execute(httpGet);
			Log.d(TAG, "resp;" + resp);
			if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
				Log.d(TAG, "httpGet fail, status code = " + resp.getStatusLine().getStatusCode());
				return null;
			}

			return EntityUtils.toByteArray(resp.getEntity());

		} catch (Exception e) {
			Log.d(TAG, "httpGet exception, e = " + e.getMessage());
			e.printStackTrace();
			return null;
		}
	}
      这里再说一下http和https的区别,后者其实就是在前者的基础上加了一层安全套接字SSL,https服务器所使用的根证书是自签名的。如果设备的信任证书列表中不包含此签名机构,就会连接失败。出现这样的问题,一般有两种解决方案:1一种是让客户端信任所有的服务器证书,这种方法安全性则差一些,但实现相对简单。另一种是在发起https连接之前将服务器证书加到httpclient的信任证书列表中,这个相对来说比较复杂一些,但容易出错,第一种使用方式就是最上面的这两行代码,实现也比较简单:

       SSLContext sslctxt = SSLContext.getInstance("TLS"); // 为请求通TLS协议,生成SSLContext对象
       sslctxt.init(null, new TrustManager[] { new MyX509TrustManager() },new java.security.SecureRandom());// 初始化SSLContext
    第二种方式就是微信支付Demo中的,在发起https请求的时候把keystore签名作为证书并在服务器端验证,具体代码:
       KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
       trustStore.load(null, null); 
       Log.d(TAG, "trustStore: " + new String(trustStore.toString()));
       SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore); 
       sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); 
       .....
       public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {      
            super(truststore);      
          
            TrustManager tm = new X509TrustManager() {      
          
                public X509Certificate[] getAcceptedIssuers() {      
                    return null;      
                }      
          
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws java.security.cert.CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain,    String authType) throws java.security.cert.CertificateException {
                }  
            };      
          
            sslContext.init(null, new TrustManager[] { tm }, null);      
     }   
     下面主要说OkHttp的使用,首先要支持Android2.3和jdk1.7以上,官方文档https://github.com/square/okhttp/wiki/Recipes,其实官方文档已经说的很详细了,我们照着来写例子就行了,不得不说这种文档确实是干活,唯一就是英文,不过既然选择了这个行业,这点困难还是要克服的,慢慢积累吧,总的来说OkHttp实现了几乎实现了和HttpURLConnection一样的API ,我们参照上面的两种例子进行OkHttp的封装,看代码确实简洁了一些,要注意最新的OkHttp采用FormBody来实现带参数的Post请求,原来的用的是 FormEncodingBuilder这个类,总不敢接起来就三步,第一,new一个Builder来设置证书,同时实例化OkHttpClient,第二,FormBody设置参数,Request完成请求,最后一步OKHttpClient对象返回response,判断结果输出,当然这只是POST方式提交键值对,还有POST提交文件、响应头、流、表单,还有OkHttpGet的get方式,仔细参考API文档,多写一些测试代码相信大家也会掌握,

   public static String post(String httpsUrl, String params) {
		String result = null;
		SSLContext sslctxt;
		try {
			// 为请求通TLS协议,生成SSLContext对象
			// 初始化SSLContext
			sslctxt = SSLContext.getInstance("TLS");
			sslctxt.init(null, new TrustManager[] { new MyX509TrustManager() },new java.security.SecureRandom());		
			OkHttpClient.Builder builder = new Builder();
			builder.sslSocketFactory(sslctxt.getSocketFactory());
			builder.hostnameVerifier(new MyHostnameVerifier());
			OkHttpClient client = new OkHttpClient();
			FormBody formBody = new FormBody.Builder()
					.add("plat", params)
					.build();
			Request request = new Request.Builder().url(httpsUrl).post(formBody).build();
			Response response = client.newCall(request).execute();
			if(response.isSuccessful()) {
				return response.body().toString();
			} else {
				throw new IOException("Unexpected code " + response);
			}		
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (KeyManagementException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
     说了这么多,谷歌为什么推出OkHttp,还是有原因的,OkHttp 处理了很多网络疑难杂症:会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。相信大家以前在用HttpUrlConnection和HttpClient的时候也遇到了很多问题,因此为了BUG少一点,还是尽快使用OkHttp,毕竟在Android studio上使用还是很方便的,最后推荐一个封装OkHttp的jar包,前面也提到了 https://github.com/hongyangAndroid/okhttp-utils,说不定用完这个后你自己也可以写一个适合项目的网络请求模块,也可以锻炼一下封装代码的能力,欢迎交流。

    本文参考http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0106/2275.html。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值