xUtils3.x的网络请求封装和请求https之单向SSL验证

很久没写博客了, 自己定的路已经走歪,菜鸟的进阶之路上我只是走了一步,自从发了一篇博客之后在没有来过这里,已经有一年了吧,今天再次回到这里。

言归正传,今天要写的是xUtils3.x网络请求的封装和请求https,最近xUtils做出了一次比较大的重构,原有的使用规则都有了新的变化。具体的变化可以去 https://github.com/wyouflf/xUtils3.git ,还有很多大神都整理了很多写了博客,需要了解的自行去看。

xUtils3.x还是和之前一样分有4大模块:注解模块,网络模块,图片加载模块,数据库模块。

在开始封装之前,我们需要把准备工作做好. 

1. 不可缺少的权限:

2. 导入jar 和 so 文件 (提供一个大神的下载地址:http://dl.bintray.com/wyouflf/maven/org/xutils/xutils/ )

如果是AS   使用Gradle 构建时添加一下依赖即可     compile 'org.xutils:xutils:3.2.2'

     使用Eclipse构建时操作步骤如下:   下载aar文件并使用然后用zip解压, 取出jar包和so文件.  将xutils-3.2.0.jar 以及armeabi添加到工程的libs中即可。

       xUtils3.x的网络请求封装和请求https之单向SSL验证_第1张图片xUtils3.x的网络请求封装和请求https之单向SSL验证_第2张图片

3.初始化  Applicationoncreate方法中加入下面代码:   

 x.Ext.init(this);
 x.Ext.setDebug(BuildConfig.DEBUG);

4.Acitivity里使用注解的话需要在Activityoncreate方法中加入下面代码
x.view().inject(this);

Fragment里注解就需要onCreateView  return x.view().inject(this, inflater, container);  

哈哈,是不是太啰嗦了,等等先。 xUtils3.x网络请求里最大的变化就是

 x.http().get(params, mCallback); x.http().post(params, mCallback);直接用x来获取。取消了HttpUtils这个类.

RequestParams params = new RequestParams(url); 在newRequestParams的时候必须要传请求接口url. 这就是在网络模块里一些的改变. 但并不是所有的。

开始上代码咯。HttpXUtils3Manager类

import java.io.InputStream;
import java.net.HttpCookie;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.List;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

import org.xutils.x;
import org.xutils.common.Callback.Cancelable;
import org.xutils.common.Callback.CommonCallback;
import org.xutils.ex.HttpException;
import org.xutils.http.HttpMethod;
import org.xutils.http.RequestParams;
import org.xutils.http.cookie.DbCookieStore;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager.NameNotFoundException;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.TypeReference;
import com.lidroid.xutils.http.HttpHandler;
import com.ylpw.ticketapp.BuildConfig;
import com.ylpw.ticketapp.R;
import com.ylpw.ticketapp.YongLeApplication;
import com.ylpw.ticketapp.common.App;
import com.ylpw.ticketapp.common.ConstantManager;
import com.ylpw.ticketapp.common.LogManager;
import com.ylpw.ticketapp.log.Logger;
import com.ylpw.ticketapp.model.TResult;
import com.ylpw.ticketapp.model.TResultWrapper;
import com.ylpw.ticketapp.util.Base64Util;
import com.ylpw.ticketapp.util.NetworkUtils;
import com.ylpw.ticketapp.util.ToastUtils;

/**
 * xUtils3 应用与网络通讯管理类
 **/
public class HttpXUtils3Manager {

	/** Https 证书验证对象 */
    private static SSLContext s_sSLContext = null;
	private static final String TAG = "HttpXUtils3Manager";
	
	private HttpXUtils3Manager() {
	}
	
	/**
	 * http get请求
	 * 
	 * @param params 请求参数 get请求使用 addQueryStringParameter方法添加参数
	 * @param mCallback 回调对象
	 * @return 网络请求的Cancelable 可以中断请求
	 */
	public static Cancelable getHttpRequest(RequestParams params, final XUtils3Callback mCallback) {
		return sendHttpRequest(HttpMethod.GET, params, mCallback);
	}
	
	/**
	 * http post请求
	 * 
	 * @param params 请求参数 post请求使用 addBodyParameter方法添加参数
	 * @param mCallback 回调对象
	 * @return 网络请求的Cancelable 可以中断请求
	 */
	public static Cancelable postHttpRequest(RequestParams params, final XUtils3Callback mCallback) {
		return sendHttpRequest(HttpMethod.POST, params, mCallback);
	}
	
	
	/**
	 * 发送请求 Cancelable
	 * 
	 * @param method 请求方式(GET POST)
	 * @param params 请求参数
	 * @param mCallback 回调对象
	 * @return 网络请求的Cancelable 可以中断请求
	 */
	public static Cancelable sendHttpRequest(HttpMethod method, RequestParams params, final XUtils3Callback mCallback){
		if (!NetworkUtils.isNetworkAvailable(YongLeApplication.getInstance())) {// 网络请求之前先检查网络是否可用
			mCallback.onFinished();
			mCallback.onError(new TResult(), "网络连接失败,请重试");
			ToastUtils.showToast(R.string.checknetwork);
			return null;
		}
		
		if (params == null) {
			params = new RequestParams();
		}
		params.setHeader("Cookie", App.getCookie());// 设置Cookie
		params.setCacheMaxAge(1000*0); //为请求添加缓存时间
		params.setConnectTimeout(ConstantManager.CONNECTION_TIME_OUT); //超时时间60s
		
		/** Cancelable cancelable = x.http().get(params, Callback); */
		return  x.http().request(method, params , new CommonCallback() {

			@Override //取消
			public void onCancelled(CancelledException msg) {
				ToastUtils.showToast(msg.getMessage());
				mCallback.onError(new TResult(), msg.getMessage());
				mCallback.onFinished();
			}

			@Override //错误
			public void onError(Throwable arg0, boolean arg1) {
				if (arg0 instanceof HttpException) { // 网络错误
				}
				ToastUtils.showToast(arg0.getMessage());
				LogManager.i(TAG, "==> RequestCallBack.onError()");
				LogManager.e(TAG, "==> response:" + arg0.getMessage() + "\n==> error:" + arg1);
				mCallback.onError(new TResult(), arg0.getMessage());
				mCallback.onFinished();
			}

			@Override //成功
			public void onSuccess(String result) {
				if (result == null) {
					return;
				}
				LogManager.i(TAG, "==> RequestCallBack.onSuccess()");
				Logger.json(result);
				try {
					TResultWrapper wrapper = JSON.parseObject(result, new TypeReference>() {});
					TResult mTResult = wrapper.getResult();
					if (mTResult != null) {
						switch (mTResult.getCode()) {
						case 0:// 请求成功返回正常的数据
							mCallback.onSuccess(result);
							mCallback.onFinished();// 回调请求结束的方法
							break;
						default://这是失败的错误码
							mCallback.onError(mTResult, mTResult.getMessage());
							break;
						}
					} 
				} catch (JSONException e) {
					e.printStackTrace();
				}
			}
			
			@Override //完成
			public void onFinished() {
			}
		});
	}
	
	/**
	 * 中断网络请求
	 * 
	 * @param mCancelable Cancelable
	 */
	public  void interrupt(Cancelable mCancelable) {
		if (mCancelable != null && !mCancelable.isCancelled()) {
			mCancelable.cancel();
		}
	}
	
}
 
   
  

公共的请求回调类XUtils3Callback

import com.ylpw.ticketapp.model.TResult;

/**
 * 公共的请求回调类
 * 
 * xiexucheng
 */
public interface XUtils3Callback {

	/**
	 * 通讯成功,返回正常的数据时回调的方法
	 * 
	 * @param result 返回信息
	 */
	void onSuccess(String result);

	/**
	 * 请求失败、拦截到错误等,回调的方法
	 * 
	 * @param mTResult 错误信息 根据自己的项目接口的返回去model
	 * @param message 提示信息
	 */
	void onError(TResult mTResult, String message);

	/**
	 * 请求结束回调的方法
	 */
	void onFinished();

}
在Activity中使用

private void getHttpXUtilsData() {
		
        RequestParams params = new RequestParams("https://www.baidu.com");
        params.addQueryStringParameter("name", "dlx2cheng"); 
        
        HttpXUtils3Manager.getHttpRequest(params, new XUtils3Callback() {
			
			@Override
			public void onSuccess(String result) {
				//这里用的是fastjson解析
				TResultWrapper resulta = JSON.parseObject(result, new Typ						eReference>() {});
				TProductDataWrapper data = resulta.getData();
				if (data != null) {
					
				}
			}
			
			@Override
			public void onError(TResult mTResult, String message) {
				ToastUtils.showToast(message);
			}
			
			@Override
			public void onFinished() {
			}
			
		});
	}

到这里基本就是一套xUtils3.x的get和post请求的封装了。 但是.. 如果你运行成功了一定会事情失败。因为请求的是https://www.baidu.com

 
  

这是https的请求. 一般公司都有一个SSL证书,也就是crt文件或者cet文件(其实都是一样的)。 把文件放入assets或者raw文件下, 只要拿到文件就行了。

xUtils当然也提供了设置SSL的方法.   

params.setSslSocketFactory(sslContext.getSocketFactory()); //绑定SSL证书(https请求)

当然也是写在sendHttpRequest里,跟在设置超时时间后面就行了。 下面看代码:

params.setHeader("Cookie", App.getCookie());// 设置Cookie
		params.setCacheMaxAge(1000*0); //为请求添加缓存时间
		params.setConnectTimeout(ConstantManager.CONNECTION_TIME_OUT); //超时时间60s
		
		/** 判断https证书是否成功验证 */
		SSLContext sslContext = getSSLContext(YongLeApplication.getInstance());
      	if(null == sslContext){
      		if (BuildConfig.DEBUG) LogManager.d(TAG, "Error:Can't Get SSLContext!");
      		return null;
      	}
		params.setSslSocketFactory(sslContext.getSocketFactory()); //绑定SSL证书(https请求)

这里是验证SSL的方法: 我这里写了官方推荐的和官方不推荐的(信任所有证书). 其实如果用信任所有证书是不安全的和请求http没什么区别.. 所有还是建议官方推荐。

   /**
     * 获取Https的证书
     * @param context Activity(fragment)的上下文
     * @return SSL的上下文对象
     */
	private static SSLContext getSSLContext(Context context) {
		
        CertificateFactory certificateFactory = null;
        InputStream inputStream = null;
        Certificate cer = null;
        KeyStore keystore = null;
        TrustManagerFactory trustManagerFactory = null;
        try {
        	
            certificateFactory = CertificateFactory.getInstance("X.509");
            inputStream = context.getAssets().open("baidu.crt");//这里导入SSL证书文件
            
            try {
            	//读取证书
            	cer = certificateFactory.generateCertificate(inputStream);
                LogManager.i(TAG, cer.getPublicKey().toString());
            	
			} finally {
				inputStream.close();
			}

            //创建一个证书库,并将证书导入证书库
            keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            keystore.load(null,null); //双向验证时使用
            keystore.setCertificateEntry("trust", cer);
            
            // 实例化信任库
            trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            // 初始化信任库
            trustManagerFactory.init(keystore);

            s_sSLContext = SSLContext.getInstance("TLS");
            s_sSLContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            
           //信任所有证书 (官方不推荐使用)
//         s_sSLContext.init(null, new TrustManager[]{new X509TrustManager() { 
//				
//				@Override
//				public X509Certificate[] getAcceptedIssuers() {
//					return null;
//				}
//				
//				@Override
//				public void checkServerTrusted(X509Certificate[] arg0, String arg1)
//						throws CertificateException {
//					
//				}
//				
//				@Override
//				public void checkClientTrusted(X509Certificate[] arg0, String arg1)
//						throws CertificateException {
//					
//				}
//			}}, new SecureRandom());
            
            return s_sSLContext;
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
	}

在验证SSL证书的过程中很多人都会出现一个异常:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
这个异常呢也就是说证书的信任路径找不到. 当时我就报了这俩问题, 我仔细看代码没发现问题, 又上某度查了一天还是没有什么答案, 有的都是让信任所有证书,后来我突然想到看证书的有效时间才发现证书到期了!!!  赶紧找公司给了我一个新的, 放进去后完全没事了 - -.  很纠结的。 当然了, 有可能还有其他的问题会导致出现这两个异常。。

代码呢到这也基本完成了. 这里也只是写了xUtils的get和post的封装,.当然有的可能因为项目的关系封装的方式可能不一样,但总是可以参考的。

如果有发现代码不对和疑问的地方,欢迎各位来探讨. 我的QQ和邮箱:7907716、[email protected]


你可能感兴趣的:(Android菜鸟的进阶之路)