Android之网络请求3————OkHttp的拦截器和封装

一.目录

文章目录

  • Android之网络请求3————OkHttp的拦截器和封装
      • 一.目录
      • 二.OkHttp拦截器概述
        • 1.OkHttp的拦截器的作用:
        • 2.OkHttp拦截器的分类
        • 3.两种的区别
      • 三.两种拦截器的示例
        • 1.实例化appInterceptor拦截器
        • 2.实例化networkInterceptor拦截器
        • 3.将两个拦截器配置在Client中,并发送请求
        • 4.运行结果
      • 四.拦截器的实际应用
        • 1.统一添加Header
        • 2.改变请求体
      • 五.OkHttp的封装
        • 1.封装
        • 2.使用
        • 3.升级版
      • 六. 参考资料
      • 七.文章索引

二.OkHttp拦截器概述

关于OKHttp更多详细的内容,可以参考官网OKHttp官网
在OKHttp中,中Interceptors拦截器是一种强大的机制,可以监视,重写和重试Call请求。

1.OkHttp的拦截器的作用:

  • 拦截器可以一次性对所有请求的返回值进行修改
  • 拦截器可以一次性对请求的参数和返回的结果进行编码,比如统一设置为UTF-8.
  • 拦截器可以对所有的请求做统一的日志记录,不需要在每个请求开始或者结束的位置都添加一个日志操作。
  • 其他需要对请求和返回进行统一处理的需求…

2.OkHttp拦截器的分类

OkHttp中的拦截器分2个:APP层面的拦截器(Application Interception)网络请求层面的拦截器(Network Interception)。

3.两种的区别

Application:

  • 不需要担心是否影响OKHttp的请求策略和请求速度
  • 即使从缓存中取数据,也会执行Application拦截器
  • 允许重试,即Chain.proceed()可以执行多次。
  • 可以监听观察这个请求的最原始的未改变的意图(请求头,请求体等),无法操作OKHttp为我们自动添加额外的请求头
  • 无法操作中间的响应结果,比如当URL重定向发生以及请求重试,只能操作客户端主动第一次请求以及最终的响应结果

Network Interceptors

  • 可以修改OkHttp框架自动添加的一些属性,即允许操作中间响应,比如当请求操作发生重定向或者重试等。
  • 可以观察最终完整的请求参数(也就是最终服务器接收到的请求数据和熟悉)

三.两种拦截器的示例

1.实例化appInterceptor拦截器

/** * 应用拦截器 */Interceptor appInterceptor = new Interceptor() {        @Override        public Response intercept(Chain chain) throws IOException {            Request request = chain.request();            HttpUrl url = request.url();            String s = url.url().toString();                        Log.d(TAG, "app intercept:begin ");            Response response = chain.proceed(request);//请求            Log.d(TAG, "app intercept:end");            return response;        }    };

2.实例化networkInterceptor拦截器

    /**     * 网络拦截器     */    Interceptor networkInterceptor = new Interceptor() {                @Override                public Response intercept(Chain chain) throws IOException {                    Request request = chain.request();                    Log.d(TAG,"network interceptor:begin");                    Response  response = chain.proceed(request);//请求                    Log.d(TAG,"network interceptor:end");                    return response;                }            };

3.将两个拦截器配置在Client中,并发送请求

 @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        okHttpClient = new OkHttpClient                .Builder()                .addInterceptor(appInterceptor)                .addNetworkInterceptor(networkInterceptor)                .build();        Button button = findViewById(R.id.bt);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Request request = new Request.Builder().url("http://www.baidu.cn").build();                okHttpClient.newCall(request).enqueue(new Callback() {                    @Override                    public void onFailure(Call call, IOException e) {                        e.printStackTrace();                    }                    @Override                    public void onResponse(Call call, Response response) throws IOException {                        Log.d(TAG,"--" + response.networkResponse());                    }                });            }        });    }

4.运行结果

四.拦截器的实际应用

1.统一添加Header

应用场景:后台要求在请求API时,在每一个接口的请求头添加上对于的Token
这时候就可以使用拦截器对他们进行统一配置,
实例化拦截器

  Interceptor  TokenHeaderInterceptor = new Interceptor() {        @Override        public Response intercept(Chain chain) throws IOException {            // get token            String token = AppService.getToken();            Request originalRequest = chain.request();            // get new request, add request header            Request updateRequest = originalRequest.newBuilder()                    .header("token", token)                    .build();            return chain.proceed(updateRequest);        }    };

在OKHttpClient中配置

        okHttpClient = new OkHttpClient                .Builder()                .addInterceptor(TokenHeaderInterceptor)                .addNetworkInterceptor(networkInterceptor)                .build();        Button button = findViewById(R.id.bt);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Request request = new Request.Builder().url("http://www.baidu.cn").build();                okHttpClient.newCall(request).enqueue(new Callback() {                    @Override                    public void onFailure(Call call, IOException e) {                        e.printStackTrace();                    }                    @Override                    public void onResponse(Call call, Response response) throws IOException {                        Log.d(TAG, "--" + response.networkResponse());                    }                });            }        });

2.改变请求体

应用场景:在上面的 login 接口基础上,后台要求我们传过去的请求参数是要按照一定规则经过加密的。

规则:

  • 请求参数名统一为content;
  • content值:JSON 格式的字符串经过 AES 加密后的内容;、

实例化拦截器

    Interceptor  RequestEncryptInterceptor = new Interceptor() {        private static final String FORM_NAME = "content";        private static final String CHARSET = "UTF-8";        @Override        public Response intercept(Chain chain) throws IOException {            // get token            Request request = chain.request();            RequestBody body = request.body();            if (body instanceof FormBody){                FormBody formBody = (FormBody) body;                Map<String, String> formMap = new HashMap<>();                // 从 formBody 中拿到请求参数,放入 formMap 中                for (int i = 0; i < formBody.size(); i++) {                    formMap.put(formBody.name(i), formBody.value(i));                }                // 将 formMap 转化为 json 然后 AES 加密                Gson gson = new Gson();                String jsonParams = gson.toJson(formMap);                String encryptParams = AESCryptUtils.encrypt(jsonParams.getBytes(CHARSET), AppConstant.getAESKey());                // 重新修改 body 的内容                body = new FormBody.Builder().add(FORM_NAME, encryptParams).build();            }            if (body != null) {                request = request.newBuilder()                        .post(body)                        .build();            }            return chain.proceed(request);        }    };

其他的同上。

五.OkHttp的封装

封装来源于博客:OKHttp的基本使用和简单封装

1.封装

public class NetRequest {    private static NetRequest netRequest;    private static OkHttpClient okHttpClient; // OKHttp网络请求    private Handler mHandler;    private NetRequest() {        // 初始化okhttp 创建一个OKHttpClient对象,一个app里最好实例化一个此对象        okHttpClient = new OkHttpClient();        okHttpClient.newBuilder()                .connectTimeout(10, TimeUnit.SECONDS)                .readTimeout(10, TimeUnit.SECONDS)                .writeTimeout(10, TimeUnit.SECONDS);        mHandler = new Handler(Looper.getMainLooper());    }    /**     * 单例模式  获取NetRequest实例     *     * @return netRequest     */    private static NetRequest getInstance() {        if (netRequest == null) {            netRequest = new NetRequest();        }        return netRequest;    }    //-------------对外提供的方法Start--------------------------------    /**     * 建立网络框架,获取网络数据,异步get请求(Form)     *     * @param url      url     * @param params   key value     * @param callBack data     */    public static void getFormRequest(String url, Map<String, String> params, DataCallBack callBack) {        getInstance().inner_getFormAsync(url, params, callBack);    }    /**     * 建立网络框架,获取网络数据,异步post请求(Form)     *     * @param url      url     * @param params   key value     * @param callBack data     */    public static void postFormRequest(String url, Map<String, String> params, DataCallBack callBack) {        getInstance().inner_postFormAsync(url, params, callBack);    }    /**     * 建立网络框架,获取网络数据,异步post请求(json)     *     * @param url      url     * @param params   key value     * @param callBack data     */    public static void postJsonRequest(String url, Map<String, String> params, DataCallBack callBack) {        getInstance().inner_postJsonAsync(url, params, callBack);    }    //-------------对外提供的方法End--------------------------------    /**     * 异步get请求(Form),内部实现方法     *     * @param url    url     * @param params key value     */    private void inner_getFormAsync(String url, Map<String, String> params, final DataCallBack callBack) {        if (params == null) {            params = new HashMap<>();        }        // 请求url(baseUrl+参数)        final String doUrl = urlJoint(url, params);        // 新建一个请求        final Request request = new Request.Builder().url(doUrl).build();        //执行请求获得响应结果        Call call = okHttpClient.newCall(request);        call.enqueue(new Callback() {            @Override            public void onFailure(Call call, IOException e) {                deliverDataFailure(request, e, callBack);            }            @Override            public void onResponse(Call call, Response response) throws IOException {                if (response.isSuccessful()) { // 请求成功                    //执行请求成功的操作                    String result = response.body().string();                    deliverDataSuccess(result, callBack);                } else {                    throw new IOException(response + "");                }            }        });    }    /**     * 异步post请求(Form),内部实现方法     *     * @param url      url     * @param params   params     * @param callBack callBack     */    private void inner_postFormAsync(String url, Map<String, String> params, final DataCallBack callBack) {        RequestBody requestBody;        if (params == null) {            params = new HashMap<>();        }        FormBody.Builder builder = new FormBody.Builder();        /**         * 在这对添加的参数进行遍历         */        for (Map.Entry<String, String> map : params.entrySet()) {            String key = map.getKey();            String value;            /**             * 判断值是否是空的             */            if (map.getValue() == null) {                value = "";            } else {                value = map.getValue();            }            /**             * 把key和value添加到formbody中             */            builder.add(key, value);        }        requestBody = builder.build();        //结果返回        final Request request = new Request.Builder().url(url).post(requestBody).build();        okHttpClient.newCall(request).enqueue(new Callback() {            @Override            public void onFailure(Call call, IOException e) {                deliverDataFailure(request, e, callBack);            }            @Override            public void onResponse(Call call, Response response) throws IOException {                if (response.isSuccessful()) { // 请求成功                    //执行请求成功的操作                    String result = response.body().string();                    deliverDataSuccess(result, callBack);                } else {                    throw new IOException(response + "");                }            }        });    }    /**     * post请求传json     *     * @param url      url     * @param callBack 成功或失败回调     * @param params   params     */    private void inner_postJsonAsync(String url, Map<String, String> params, final DataCallBack callBack) {        // 将map转换成json,需要引入Gson包        String mapToJson = new Gson().toJson(params);        final Request request = buildJsonPostRequest(url, mapToJson);        okHttpClient.newCall(request).enqueue(new Callback() {            @Override            public void onFailure(Call call, IOException e) {                deliverDataFailure(request, e, callBack);            }            @Override            public void onResponse(Call call, Response response) throws IOException {                if (response.isSuccessful()) { // 请求成功                    //执行请求成功的操作                    String result = response.body().string();                    deliverDataSuccess(result, callBack);                } else {                    throw new IOException(response + "");                }            }        });    }    /**     * Json_POST请求参数     *     * @param url  url     * @param json json     * @return requestBody     */    private Request buildJsonPostRequest(String url, String json) {        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);        return new Request.Builder().url(url).post(requestBody).build();    }    /**     * 分发失败的时候调用     *     * @param request  request     * @param e        e     * @param callBack callBack     */    private void deliverDataFailure(final Request request, final IOException e, final DataCallBack callBack) {        /**         * 在这里使用异步处理         */        mHandler.post(new Runnable() {            @Override            public void run() {                if (callBack != null) {                    callBack.requestFailure(request, e);                }            }        });    }    /**     * 分发成功的时候调用     *     * @param result   result     * @param callBack callBack     */    private void deliverDataSuccess(final String result, final DataCallBack callBack) {        /**         * 在这里使用异步线程处理         */        mHandler.post(new Runnable() {            @Override            public void run() {                if (callBack != null) {                    try {                        callBack.requestSuccess(result);                    } catch (Exception e) {                        e.printStackTrace();                    }                }            }        });    }    /**     * 数据回调接口     */    public interface DataCallBack {        void requestSuccess(String result) throws Exception;        void requestFailure(Request request, IOException e);    }    /**     * 拼接url和请求参数     *     * @param url    url     * @param params key value     * @return String url     */    private static String urlJoint(String url, Map<String, String> params) {        StringBuilder endUrl = new StringBuilder(url);        boolean isFirst = true;        Set<Map.Entry<String, String>> entrySet = params.entrySet();        for (Map.Entry<String, String> entry : entrySet) {            if (isFirst && !url.contains("?")) {                isFirst = false;                endUrl.append("?");            } else {                endUrl.append("&");            }            endUrl.append(entry.getKey());            endUrl.append("=");            endUrl.append(entry.getValue());        }        return endUrl.toString();    }}

2.使用

        String url = "网络请求的地址";        HashMap<String, String> params = new HashMap<>();        // 添加请求参数        params.put("key", "value");        // ...        NetRequest.getFormRequest(url, params, new NetRequest.DataCallBack() {            @Override            public void requestSuccess(String result) throws Exception {                // 请求成功的回调            }            @Override            public void requestFailure(Request request, IOException e) {                // 请求失败的回调            }        });        

3.升级版

还发现一篇封装的更彻底OKHttp
推荐一下

OkHttp封装

六. 参考资料

OkHttp基本使用(五)拦截器
一起来写OKHttp的拦截器
OkHttp3-拦截器(Interceptor)
OKHttp的基本使用和简单封装
OkHttp封装

七.文章索引

Android之网络请求1————HTTP协议
Android之网络请求2————OkHttp的基本使用
Android之网络请求3————OkHttp的拦截器和封装
Android之网络请求4————OkHttp源码1:框架
Android之网络请求5————OkHttp源码2:发送请求
Android之网络请求6————OkHttp源码3:拦截器链
Android之网络请求7————OkHttp源码4:网络操作
Android之网络请求8————OkHttp源码5:缓存相关
Android之网络请求9————Retrofit的简单使用
Android之网络请求10————Retrofit的进阶使用
Android之网络请求11————Retrofit的源码分析

更多相关文章

  1. 《ZigBee开发笔记》第六部分 项目篇 基于ZigBee和Openwrt的智能
  2. Android换肤功能设计与实现(5)——网络加载及图片内存管理
  3. android 仿ios 对话框已封装成工具类
  4. android 仿ios 对话框已封装成工具类
  5. Android之Http请求基础
  6. android 判断是否有可用网络
  7. Android中通过pid获取app包名
  8. Android(安卓)应用程序主动请求Vsync
  9. android http中请求访问添加 cookie

随机推荐

  1. 让你大开眼界的10款Android界面设计
  2. Android用户界面设计:框架布局
  3. 触摸屏(TP)乱跳原因总结
  4. Android简单计算器实现
  5. 编程回忆之Android回忆(蓝牙BluetoothAdap
  6. mono for android 第三课--页面布局
  7. android volley解析与二次封装
  8. Android获取root权限的利弊关系
  9. android Activity布局初步(三)- 相对布局
  10. Ohone SDK的模拟器居然不能联网??