OkHttp中Interceptor拦截器之公共参数请求封装
2017-02-25 18:31
323 查看
前言
之前在面试的时候遇到这样的一个问题,那就是如果app中所有的请求都要加入一些参数(例如 版本号、手机号、登录用户名、token等。。。)那么怎么做才能实现,而不至于在每次请求的时候都去进行添加这些请求头。其实这个问题,刚开始我是拒绝的(之前没有遇到过这样的需求)。当时只是想着可以使用okhttp体用的拦截器Interceptor来进行实现,但是具体的实现还是来到了今天。Interceptor说明
在okhttp-wiki里面专门有一篇介绍Interceptor的(点击我跳转到Interceptor链接)里面有这样的一句话Interceptors are a powerful mechanism that can monitor, rewrite, and retry calls.
拦截器是一种强大的机制,可以监视、重写和重试调用
Interceptor几大作用
Application Interceptors 应用拦截器
Network Interceptors 网络拦截器
Choosing between application and network interceptors 在应用和网络拦截器之间做选择
Rewriting Requests 重写请求
Rewriting Responses 重写响应
具体的作用简介这里不再赘述,这里推荐一篇翻译的文章(Okhttp-wiki 之 Interceptors 拦截器)
进入主题
先来看下我们的需求需求约束
1、API Base Url : http://111.111.111.11:8082/xxxxx/xx(类似)2、客户端请求API的数据格式为json形式:
{ "publicParams":{}, "key1":value, "key2":value }
其中publicParams为公共参数,每个API接口必须传递
3、公共参数
字段 | 类型 | 说明 |
---|---|---|
imei | string | 移动设备身份(非必须) |
model | 手机型号、设备名称 | |
la | string | 系统语言 |
resolution | string | 分辨率(格式:1920*1080) |
densityScaleFactor | string | 密度比例 |
sdk | int | SDK版本号 |
os | string | 系统源代码控制值 |
解决方法
我们就是利用Interceptor拦截器,对每次的网络请求进行拦截,然后拿到请求url,并对url进行改造来加入我们需要的公共参数,进行和请求参数的拼接,然后构造request,通过chain.proceed(request)进行改造。第一步
构建一个CommonParamsInterceptor.class类继承自Interceptor复写intercept(Chain chain)方法,我们需要用到chain.request()来获取到request对象
request里面的方法
这里我们只需要用到url()方法(主要获取到api地址和请求参数,并进行改造),用到method()方法来判断get请求和post请求。
这个时候我们看下代码怎么进行编写吧。
commomParamsMap = new HashMap(); commomParamsMap.put(Constants.IMEI, DeviceUtils.getIMEI(mContext)); commomParamsMap.put(Constants.MODEL, DeviceUtils.getModel()); commomParamsMap.put(Constants.LANGUAGE, DeviceUtils.getLanguage()); commomParamsMap.put(Constants.os, DeviceUtils.getBuildVersionIncremental()); commomParamsMap.put(Constants.RESOLUTION, DensityUtil.getScreenW(mContext) + "*" + DensityUtil.getScreenH(mContext)); commomParamsMap.put(Constants.SDK, DeviceUtils.getBuildVersionSDK() + ""); commomParamsMap.put(Constants.DENSITY_SCALE_FACTOR, mContext.getResources().getDisplayMetrics().density + ""); //get请求的封装 if (method.equals("GET")) { //获取到请求地址api HttpUrl httpUrlurl = request.url(); HashMap rootMap = new HashMap(); //通过请求地址(最初始的请求地址)获取到参数列表 Set parameterNames = httpUrlurl.queryParameterNames(); for (String key : parameterNames) { //循环参数列表 if (Constants.PARM.equals(key)) { //判断是否有匹配的字段 这个类似于 /xxx/xxx?p={} 匹配这个p String oldParamsJson = httpUrlurl.queryParameter(Constants.PARM); if (oldParamsJson != null) { //因为有的是没有这个p={"page":0} 而是直接/xxx/index的 HashMap p = mGson.fromJson(oldParamsJson, HashMap.class); //原始参数 if (p != null) { for (Map.Entry entry : p.entrySet()) { rootMap.put(entry.getKey(), entry.getValue()); } } } } else { rootMap.put(key, httpUrlurl.queryParameter(key)); } } //String oldParamJson = httpUrlurl.queryParameter(Constants.PARM); // if (oldParamJson != null) { // // } //把原来请求的和公共的参数进行组装 rootMap.put("publicParams", commomParamsMap); //重新组装 String newJsonParams = mGson.toJson(rootMap); //装换成json字符串 String url = httpUrlurl.toString(); int index = url.indexOf("?"); if (index > 0) { url = url.substring(0, index); } url = url + "?" + Constants.PARM + "=" + newJsonParams; //拼接新的url request = request.newBuilder().url(url).build(); //重新构建请求 //post请求的封装 } else if (method.equals("POST")) { // FormBody.Builder builder = new FormBody.Builder(); // builder.addEncoded("phone","phone"); RequestBody requestBody = request.body(); HashMap rootMap = new HashMap(); if (requestBody instanceof FormBody) { for (int i = 0; i < ((FormBody) requestBody).size(); i++) { rootMap.put(((FormBody) requestBody).encodedName(i), ((FormBody) requestBody).encodedValue(i)); } } else { //buffer流 Buffer buffer = new Buffer(); requestBody.writeTo(buffer); String oldParamsJson = buffer.readUtf8(); rootMap = mGson.fromJson(oldParamsJson, HashMap.class); //原始参数 rootMap.put("publicParams", commomParamsMap); //重新组装 String newJsonParams = mGson.toJson(rootMap); //装换成json字符串 request = request.newBuilder().post(RequestBody.create(JSON, newJsonParams)).build(); } } } catch (JsonSyntaxException e) { e.printStackTrace(); } //最后通过chain.proceed(request)进行返回 return chain.proceed(request); }" data-snippet-id="ext.78db2d79cdbd9c5a4c4125ead35fbb46" data-snippet-saved="false" data-codota-status="done">[code] @Override public Response intercept(Chain chain) throws IOException { //获取到request Request request = chain.request(); //获取到方法 String method = request.method(); //公共参数hasmap try { //添加公共参数 HashMap<String, Object> commomParamsMap = new HashMap<>(); commomParamsMap.put(Constants.IMEI, DeviceUtils.getIMEI(mContext)); commomParamsMap.put(Constants.MODEL, DeviceUtils.getModel()); commomParamsMap.put(Constants.LANGUAGE, DeviceUtils.getLanguage()); commomParamsMap.put(Constants.os, DeviceUtils.getBuildVersionIncremental()); commomParamsMap.put(Constants.RESOLUTION, DensityUtil.getScreenW(mContext) + "*" + DensityUtil.getScreenH(mContext)); commomParamsMap.put(Constants.SDK, DeviceUtils.getBuildVersionSDK() + ""); commomParamsMap.put(Constants.DENSITY_SCALE_FACTOR, mContext.getResources().getDisplayMetrics().density + ""); //get请求的封装 if (method.equals("GET")) { //获取到请求地址api HttpUrl httpUrlurl = request.url(); HashMap<String, Object> rootMap = new HashMap<>(); //通过请求地址(最初始的请求地址)获取到参数列表 Set<String> parameterNames = httpUrlurl.queryParameterNames(); for (String key : parameterNames) { //循环参数列表 if (Constants.PARM.equals(key)) { //判断是否有匹配的字段 这个类似于 /xxx/xxx?p={} 匹配这个p String oldParamsJson = httpUrlurl.queryParameter(Constants.PARM); if (oldParamsJson != null) { //因为有的是没有这个p={"page":0} 而是直接/xxx/index的 HashMap<String, Object> p = mGson.fromJson(oldParamsJson, HashMap.class); //原始参数 if (p != null) { for (Map.Entry<String, Object> entry : p.entrySet()) { rootMap.put(entry.getKey(), entry.getValue()); } } } } else { rootMap.put(key, httpUrlurl.queryParameter(key)); } } //String oldParamJson = httpUrlurl.queryParameter(Constants.PARM); // if (oldParamJson != null) { // // } //把原来请求的和公共的参数进行组装 rootMap.put("publicParams", commomParamsMap); //重新组装 String newJsonParams = mGson.toJson(rootMap); //装换成json字符串 String url = httpUrlurl.toString(); int index = url.indexOf("?"); if (index > 0) { url = url.substring(0, index); } url = url + "?" + Constants.PARM + "=" + newJsonParams; //拼接新的url request = request.newBuilder().url(url).build(); //重新构建请求 //post请求的封装 } else if (method.equals("POST")) { // FormBody.Builder builder = new FormBody.Builder(); // builder.addEncoded("phone","phone"); RequestBody requestBody = request.body(); HashMap<String, Object> rootMap = new HashMap<>(); if (requestBody instanceof FormBody) { for (int i = 0; i < ((FormBody) requestBody).size(); i++) { rootMap.put(((FormBody) requestBody).encodedName(i), ((FormBody) requestBody).encodedValue(i)); } } else { //buffer流 Buffer buffer = new Buffer(); requestBody.writeTo(buffer); String oldParamsJson = buffer.readUtf8(); rootMap = mGson.fromJson(oldParamsJson, HashMap.class); //原始参数 rootMap.put("publicParams", commomParamsMap); //重新组装 String newJsonParams = mGson.toJson(rootMap); //装换成json字符串 request = request.newBuilder().post(RequestBody.create(JSON, newJsonParams)).build(); } } } catch (JsonSyntaxException e) { e.printStackTrace(); } //最后通过chain.proceed(request)进行返回 return chain.proceed(request); }
第二步
当我们把自定义的Interceptor构建完成之后,我们需要在Okhttp中进行使用。return new OkHttpClient.Builder() //HeadInterceptor 实现了Intercepter 用来网Request Header添加一些相关数据 如APP版本 token信息 // .addInterceptor(new HttpLoggingInterceptor()) //添加自定义的拦截器,完成公共参数的封装 .addInterceptor(new CommonParamsInterceptor(gson,application)) .connectTimeout(10, TimeUnit.SECONDS)//链接超时 .readTimeout(10, TimeUnit.SECONDS)//设置读取超时 .build();
这个时候就可以了,我们来看下拦截之前和加入拦截器之后的请求url,看看是否起到了作用。
这个时候我们debug一下看下就明白了。
我们可以看到下图中上面的参数是只有一个,但是第二行就已经改变了,添加过了我们需要的公共参数,并且还有我们请求的参数。符合我们的要求。
参考文章
Okhttp-wiki 之 Interceptors 拦截器Okhttp-wiki之Interceptors
相关文章推荐
- 自定义的拦截器,封装公共参数 get请求
- okhttp自定义拦截器,封装公共参数,get或post请求不同的拦截器
- OKHttp使用拦截器(Interceptor)POST与GET方法,统一封装传公共参数
- OkHttp封装,以及拦截器,拦截公共参数
- OkHttp3 拦截器 封装公共参数
- Retrofit网络请求封装公共参数GET和POST请求
- Rxjava+retrofit 添加公共请求参数及请求结果封装
- OKHTTP封装公共参数
- 自定义拦截器封装公共请求参数
- OKHTTP带公共参数封装在方法中的工具类
- Okhttp 请求添加公共参数、公共Headers 方法
- 微信公共号开发教程java版——请求消息,响应消息及事件消息类的封装(三)
- RxJava+Retrofit+OkHttp深入浅出-终极封装二(网络请求)
- 封装请求参数Page对象
- 把request对象中的请求参数封装到bean中/生成UUID
- Android RxJava+Retrofit+OkHttp深入浅出-终极封装二(网络请求)
- OkHttp的基本使用-3(添加拦截器和GET请求的参数拼接)
- Retrofit简单封装使用--Post请求封装请求体、Get请求通过参数、map方式构建url
- OkHttp框架二次封装,post json格式的参数(上)
- Android网络请求使用Retrofit+OkHttp,如何获取请求参数 ?