通过Http协议获取网络资源,OkHttpClient的使用
所需要的jar包: okhttp-3.0.0-RC1.jar 与 okio-1.6.0.jar (okhttp内部依赖okio)
OkHttpClient分同步请求与异步请求,这就是最大的不同了
Get方式的同步请求:
/** * 通过get的方式请求数据,这里为同步请求,需要在子线程中运行 */ private void getGetData() { try { //1.声名okhttp客户端 OkHttpClient okHttpClient = new OkHttpClient(); //2.设置请求方式,设置请求参数 Request request = new Request.Builder().get().url("网址").build(); //3.获得请求结果 Response response = okHttpClient.newCall(request).execute(); if (response.isSuccessful()) {//判断请求是否成功 //获得相应的实体 ResponseBody body = response.body(); String string = body.string();//获得String byte[] bytes = body.bytes();//获得byte[] InputStream inputStream = body.byteStream();//获得流 } } catch (IOException e) { e.printStackTrace(); } }
Get方式的异步请求:
/** * 通过get方式请求数据,这里为异步请求,不需要另开子线程,内部是在子线程中运行的 */ private void getAsyncOkHttp() { //1.声名okhttp客户端 OkHttpClient okHttpClient = new OkHttpClient(); //2.设置请求方式,设置请求参数 Request request = new Request.Builder().get().url("网址").build(); //注意区别,同步是这样的:okHttpClient.newCall(request).execute(); okHttpClient.newCall(request).enqueue(new Callback() {//异步 @Override //请求数据失败的回调 public void onFailure(Request request, IOException e) { } @Override //请求数据成功的回调,子线程中运行的 可以判断下状态码 response.code() public void onResponse(Response response) throws IOException { String string = response.body().string();//获得String byte[] bytes = response.body().bytes();//获得byte[] InputStream inputStream = response.body().byteStream();//获得流 } }); }
POST
public static final OkHttpClient client = new OkHttpClient();
//post json public static Response postByH5(String url, Map<String, String> header, String json) throws IOException { if (header == null) { header = new HashMap(); } RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .headers(Headers.of(header)) .post(body) .build(); Response response = client.newCall(request).execute(); return response; } //表单同步 public static Response postFromByH5(String url, Map<String, String> header, String json) throws IOException { if (header == null) { header = new HashMap(); } HashMap<String, String> hashMap = new Gson().<HashMap<String, String>>fromJson(json, HashMap.class); FormBody.Builder builder = new FormBody.Builder(); if (hashMap != null) { Iterator<Map.Entry<String, String>> entries = hashMap.entrySet().iterator(); while (entries.hasNext()) { Map.Entry<String, String> entry = entries.next(); builder.add(entry.getKey(), entry.getValue()); } } FormBody formBody = builder.build(); Request request = new Request.Builder() .url(url) .headers(Headers.of(header)) .post(formBody) .build(); Response response = client.newCall(request).execute(); return response; }
一些状态码的说明:
添加拦截器:
import android.text.TextUtils; import com.google.gson.Gson; import com.shch.nursingworkers.App; import com.shch.nursingworkers.bean.BaseBena; import com.shch.nursingworkers.utils.ConstantUtil; import com.shch.nursingworkers.utils.LogUtil; import com.shch.nursingworkers.utils.encrypt.AESUtil; import com.shch.nursingworkers.utils.encrypt.EncryptUtil; import com.shch.nursingworkers.utils.encrypt.RSAUtil; import com.zhy.http.okhttp.OkHttpUtils; import com.zhy.http.okhttp.callback.StringCallback; import java.io.IOException; import java.util.Locale; import okhttp3.Call; import okhttp3.Interceptor; import okhttp3.MediaType; import okhttp3.Request; import static com.shch.nursingworkers.utils.data.UrlUtils.login; /** * okhttp的拦截器 */ public class LogInterceptor implements Interceptor { @Override public okhttp3.Response intercept(Chain chain) throws IOException { Request request = chain.request(); //打印请求的网址 //LogUtil.e("request:" + request.toString()); LogUtil.e("request:" + URLDecoder.decode(request.toString(), "utf-8"));//避免乱码 long t1 = System.nanoTime(); okhttp3.Response response = chain.proceed(chain.request()); long t2 = System.nanoTime(); //打印请求头 网址 与 消耗的时间 LogUtil.e(String.format(Locale.getDefault(), "Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers())); okhttp3.MediaType mediaType = response.body().contentType(); //是文本类型的数据,才去打印请求结果 if(mediaType != null && isText(mediaType)) { String content = response.body().string(); try{ //防止下载apk或者其他文件时,解析出错 拿到请求的json数据后,这里你想干嘛就干嘛吧 //BaseBena baseBena = new Gson().fromJson(content, BaseBena.class); //打印请求的内容 LogUtil.e("response body:" + content); //复制一个请求转给外面的请求回调 return response.newBuilder() .body(okhttp3.ResponseBody.create(mediaType, content)) .build(); }catch (Exception e){ } } return response; } /** * 判断请求的内容是否是文本,防止请求的url是apk或者其他文件时,出现错误(比如:我在下载一个19兆的apk文件时,最后下下来变成了35兆) * @param mediaType * @return */ private boolean isText(MediaType mediaType){ if (mediaType.type() != null && mediaType.type().equals("text")){ return true; } if (mediaType.subtype() != null){ if (mediaType.subtype().equals("json") || mediaType.subtype().equals("xml") || mediaType.subtype().equals("html") || mediaType.subtype().equals("webviewhtml")) return true; } return false; } }
拦截器的添加与Session持久化
//Session持久化 在Application的onCreate()方法中初始化 CookieJarImpl cookieJar = new CookieJarImpl(new PersistentCookieStore(getApplicationContext())); OkHttpClient okHttpClient = new OkHttpClient.Builder() .cookieJar(cookieJar) .connectTimeout(15000L, TimeUnit.MILLISECONDS) .readTimeout(15000L, TimeUnit.MILLISECONDS) .addInterceptor(new LogInterceptor())//添加拦截器 .build(); OkHttpUtils.initClient(okHttpClient);
效果如下:
建议先看另一篇 okhttp的拦截器执行流程详解
过期后自动登录,获取新的SessionId
import com.google.gson.Gson; import com.shch.nursingworkers.App; import com.shch.nursingworkers.bean.BaseBena; import com.shch.nursingworkers.utils.ConstantUtil; import com.shch.nursingworkers.utils.LogUtil; import com.shch.nursingworkers.utils.encrypt.AESUtil; import com.shch.nursingworkers.utils.encrypt.EncryptUtil; import com.shch.nursingworkers.utils.encrypt.RSAUtil; import com.zhy.http.okhttp.OkHttpUtils; import com.zhy.http.okhttp.callback.StringCallback; import com.zhy.http.okhttp.request.RequestCall; import java.io.IOException; import java.net.URLDecoder; import java.util.Locale; import okhttp3.Call; import okhttp3.Interceptor; import okhttp3.MediaType; import okhttp3.Request; import okhttp3.Response; import static com.shch.nursingworkers.utils.data.UrlUtils.login; /** * okhttp的拦截器 */ public class LogInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request();//请求的相关信息 //打印请求的网址 //LogUtil.e("request:" + request.toString()); LogUtil.e("request:" + URLDecoder.decode(request.toString(), "utf-8")); long t1 = System.nanoTime(); okhttp3.Response response = chain.proceed(chain.request());//继续请求,拿到请求数据 long t2 = System.nanoTime(); //打印请求头 网址 与 消耗的时间 LogUtil.e(String.format(Locale.getDefault(), "Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers())); Response.Builder builder = response.newBuilder(); Response clone = builder.build();//先克隆一个响应,来打印日志 okhttp3.MediaType mediaType = clone.body().contentType(); //是文本内向的数据,才去打印请求结果 if(mediaType != null && isText(mediaType)) { String content = clone.body().string(); try{ //防止下载apk时,解析出错 BaseBena baseBena = new Gson().fromJson(content, BaseBena.class); //打印请求的内容 LogUtil.e("response body:" + content); if(baseBena!=null && "unlogin".equals(baseBena.getMessage())){ /*//未登录就登录*/ response.body().close();//先关闭该接口的资源(不会回调) Request loginRequest = getLoginRequest();//获取登陆的Request Response loginResponse = chain.proceed(loginRequest);//执行登陆,获取新的SessionId if (loginResponse.isSuccessful()) {//登陆成功(200 ~ 300) loginResponse.body().close();//释放登陆成功的资源 return chain.proceed(request);//重新执行最开始的接口 } } //复制一个请求转给外面的请求回调 return response.newBuilder() .body(okhttp3.ResponseBody.create(mediaType, content)) .build(); }catch (Exception e){ } }else{ if(mediaType == null){ LogUtil.e("拦截器,mediaType=" + mediaType);//可能是后台返回的空白页,没有返回数据类型,如没有这个头:Content-Type: application/json;charset=utf-8 response.close(); } } return response; } /** * 判断请求的内容是否是文本,防止请求的url是apk或者其他文件时,出现错误 * @param mediaType * @return */ private boolean isText(MediaType mediaType){ if (mediaType.type() != null && mediaType.type().equals("text")){ return true; } if (mediaType.subtype() != null){ if (mediaType.subtype().equals("json") || mediaType.subtype().equals("xml") || mediaType.subtype().equals("html") || mediaType.subtype().equals("webviewhtml")) return true; } return false; } /** * 防止Session过时 */ public Request getLoginRequest() throws IOException { String username = App.getSharedPreferences().getString(ConstantUtil.SP_LOGIN_NUMBER,""); String password = App.getSharedPreferences().getString(ConstantUtil.SP_LOGIN_PASSWORD,""); //加密的处理,RSA加密AES钥匙,再加密内容 //生成AES秘钥 byte[] aeskey = AESUtil.generateKey2byte(); //RSA加密AES的秘钥 byte[] aeskeyToRsa = RSAUtil.encryptByPublicKey(aeskey, RSAUtil.PUBLICKEY); final RequestCall build = OkHttpUtils .get() .url(login) .addParams("key", EncryptUtil.parseByte2HexStr(aeskeyToRsa))//将加了密的AES秘钥给服务器 //用户名与密码的加密 .addParams("username", AESUtil.encrypt2String(username, aeskey)) .addParams("password", AESUtil.encrypt2String(password, aeskey)) .addParams("loginType", "E") .build(); return build.buildCall(null).request(); } }