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

来源:互联网 发布:java web 七牛云接口 编辑:程序博客网 时间:2024/04/30 12:41

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

言归正传,今天要写的是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中即可。

       

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类

<span style="font-weight: normal;">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());// 设置Cookieparams.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<String>() {@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<Object> wrapper = JSON.parseObject(result, new TypeReference<TResultWrapper<Object>>() {});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 <T> void interrupt(Cancelable mCancelable) {if (mCancelable != null && !mCancelable.isCancelled()) {mCancelable.cancel();}}}</span>

公共的请求回调类XUtils3Callback

<span style="font-weight: normal;">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();}</span>
在Activity中使用

private void getHttpXUtilsData() {        RequestParams params = new RequestParams("https://www.baidu.com");        params.addQueryStringParameter("name", "dlx2cheng");                 HttpXUtils3Manager.getHttpRequest(params, new XUtils3Callback() {@Overridepublic void onSuccess(String result) {//这里用的是fastjson解析TResultWrapper<TProductDataWrapper> resulta = JSON.parseObject(result, new Typ<span style="white-space:pre"></span>eReference<TResultWrapper<TProductDataWrapper>>() {});TProductDataWrapper data = resulta.getData();if (data != null) {}}@Overridepublic void onError(TResult mTResult, String message) {ToastUtils.showToast(message);}@Overridepublic 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());// 设置Cookieparams.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、dlx2cheng@sina.com


6 0
原创粉丝点击