OKHttp拦截器(Interceptor)

 

一.拦截器一般作用

 

<1> URL重定向。

 

<2> 请求体数据加密。

 

<3> HEAD动态添加。

 

<4> 请求日志抓取。

 

 

 

 

 

二.基础讲解

 

<1> 创建新类实现Interceptor接口

public class CustomInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        return null;
    }
}

这样,一个拦截器就算完成,具体的实现都在intercept方法中通过操作chain对象来实现。

 

 

 

<2> 添加(注册)拦截器

有两种方法将上面的拦截器添加到OKhttp中。

 

方法1:addInterceptor方法

private RxAndroidOkhttp(){
    //创建okhttp对象 以及连接,读,取超时时间
    mOkHttpClient=new OkHttpClient.Builder()
           .connectTimeout(DataConstant.nettimeout, TimeUnit.SECONDS)//连接时间
           .readTimeout(DataConstant.nettimeout,TimeUnit.SECONDS)//读时间
           .writeTimeout(DataConstant.nettimeout,TimeUnit.SECONDS)//写时间

           .addInterceptor(new CustomInterceptor())//添加拦截器

           .build();
}

 

方法2:addNetworkInterceptor方法

private RxAndroidOkhttp(){
   //创建okhttp对象 以及连接,读,取超时时间
   mOkHttpClient=new OkHttpClient.Builder()
          .connectTimeout(DataConstant.nettimeout, TimeUnit.SECONDS)//连接时间
          .readTimeout(DataConstant.nettimeout,TimeUnit.SECONDS)//读时间
          .writeTimeout(DataConstant.nettimeout,TimeUnit.SECONDS)//写时间

          .addNetworkInterceptor(new CustomInterceptor())//添加拦截器

          .build();
}

 

 

 

 

 

 

三.拦截器具体使用之 URL重定向

 

代码

package com.wjn.okhttpmvpdemo.mode.Interceptor;

import com.wjn.okhttpmvpdemo.MyApplication;
import com.wjn.okhttpmvpdemo.mode.constant.DataConstant;
import com.wjn.okhttpmvpdemo.mode.constant.StringConstant;
import com.wjn.okhttpmvpdemo.mode.utils.BooleanUtils;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import rx.Observable;
import rx.Subscriber;

/**
 * Created by wjn on 2017/11/22.
 * OkHttp框架 封装方法
 */

public class InterceptorRxAndroidOkhttp {

    private OkHttpClient mOkHttpClient = null;//OkHttpClient 对象
    private static InterceptorRxAndroidOkhttp mRxAndroidOkhttp = null;//RxAndroidOkhttp 对象

    /**
     * 构造方法私有化
     */

    private InterceptorRxAndroidOkhttp() {
        //创建okhttp对象 以及连接,读,取超时时间
        mOkHttpClient = new OkHttpClient.Builder()
                .connectTimeout(DataConstant.nettimeout, TimeUnit.SECONDS)//连接时间
                .readTimeout(DataConstant.nettimeout, TimeUnit.SECONDS)//读时间
                .writeTimeout(DataConstant.nettimeout, TimeUnit.SECONDS)//写时间
                .addInterceptor(new CustomInterceptor())//添加拦截器
                .build();
    }

    /**
     * 获取此单例类对象的方法
     */

    public static InterceptorRxAndroidOkhttp getInstance() {
        if (null == mRxAndroidOkhttp) {//单例对象为空
            synchronized (InterceptorRxAndroidOkhttp.class) {
                mRxAndroidOkhttp = new InterceptorRxAndroidOkhttp();
            }
        }
        return mRxAndroidOkhttp;
    }

    /**
     * get请求方法
     */

    /**
     * get请求方法
     */

    public Observable<String> get(final String url) {
        //创建被观察者
        Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                final Subscriber mSubscriber = subscriber;
                //没有取消订阅的时候
                if (!mSubscriber.isUnsubscribed()) {
                    //get请求
                    Request request = new Request.Builder()
                            .url(url)
                            .get()
                            .build();
                    if (null != mOkHttpClient) {
                        mOkHttpClient.newCall(request).enqueue(new Callback() {
                            @Override
                            public void onFailure(Call call, IOException e) {
                                //通知订阅者的错误信息
                                mSubscriber.onError(e);
                            }

                            @Override
                            public void onResponse(Call call, Response response) throws IOException {
                                if (null != response) {//response 不为空
                                    if (response.isSuccessful()) {//response 请求成功
                                        //通知订阅者的成功信息
                                        mSubscriber.onNext(response.body().string());
                                    } else {//response 请求失败
                                        //通知订阅者的错误信息
                                        IOException IOExceptionx = new IOException();
                                        mSubscriber.onError(IOExceptionx);
                                    }
                                } else {//response 为空
                                    //通知订阅者的错误信息
                                    IOException IOExceptionx = new IOException();
                                    mSubscriber.onError(IOExceptionx);
                                }
                                //通知完毕
                                mSubscriber.onCompleted();
                            }
                        });
                    }
                }
            }
        });
        return observable;
    }

}

 

package com.wjn.okhttpmvpdemo.mode.Interceptor;

import android.util.Log;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class CustomInterceptor implements Interceptor {

    private String newHost = "://api.svipmovie.com";

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {

        Request request = chain.request();
        HttpUrl url = request.url();

        String scheme = url.scheme();
        String host = url.host();
        String path = url.encodedPath();
        String query = url.encodedQuery();

        Log.d("TAG","原url----:"+url.toString());
        Log.d("TAG","---------------分解原url---------------------");
        Log.d("TAG","scheme----:"+scheme);
        Log.d("TAG","host----:"+host);
        Log.d("TAG","path----:"+path);
        Log.d("TAG","query----:"+query);

        //全部参数Key
        Set<String> collection = url.queryParameterNames();
        Iterator<String> iterable = collection.iterator();
        String key = "";
        while (iterable.hasNext()) {
            key = key + iterable.next() + "###";
        }
        Log.d("TAG","key:"+key);

        //全部参数Value
        Set<String> collections = url.queryParameterNames();
        Iterator<String> iterables = collections.iterator();
        String value = "";
        while (iterables.hasNext()) {
            value = value + url.queryParameter(iterables.next()) + "###";
        }
        Log.d("TAG","value:"+value);

        StringBuffer sb = new StringBuffer();
        String newUrl = sb.append(scheme).append(newHost).append(path).append("?").append(query).toString();
        Log.d("TAG","新url----:"+newUrl);

        Request.Builder builder = request.newBuilder().url(newUrl);
        return chain.proceed(builder.build());
    }
}

 

package com.wjn.okhttpmvpdemo.view.impl.activity;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.wjn.okhttpmvpdemo.R;
import com.wjn.okhttpmvpdemo.mode.Interceptor.InterceptorRxAndroidOkhttp;
import com.wjn.okhttpmvpdemo.mode.utils.ui.StatusBarUtil;

import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

public class InterceptorActivity extends AppCompatActivity {

    private TextView textView;
    private InterceptorRxAndroidOkhttp interceptorRxAndroidOkhttp = null;//InterceptorRxAndroidOkhttp
    private Observable<String> mObservable = null;//get post 方式请求的Observable对象

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_interceptor);

        //根据状态栏颜色来决定 状态栏背景 用黑色还是白色 true:是否修改状态栏字体颜色
        StatusBarUtil.setStatusBarMode(this, true, false, R.color.baise);

        textView = findViewById(R.id.activity_interceptor_textview1);

        interceptorRxAndroidOkhttp = InterceptorRxAndroidOkhttp.getInstance();

        OkhttpTest("http://127.0.0.1/front/columns/getVideoList.do?catalogId=402834815584e463015584e539330016&pnum=1");

    }

    /**
     * 测试
     */

    private void OkhttpTest(final String geturl) {
        if (null != interceptorRxAndroidOkhttp) {
            //observable定义被观察者
            mObservable = interceptorRxAndroidOkhttp.get(geturl);
            if (null != mObservable) {
                //定义观察者
                Subscriber<String> mSubscriber = new Subscriber<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(String s) {
                        textView.setText(s);
                    }
                };

                /**
                 * 订阅者关联被观察者
                 * Schedulers.io()说明是输入输出的计划任务
                 * AndroidSchedulers.mainThread()说明订阅者是中ui主线程中执行
                 * */

                mObservable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(mSubscriber);
            }
        }
    }

}

 

结果

 

 

 

 

成功将url重定向成新的url。

 

原Url

http://127.0.0.1/front/columns/getVideoList.do?catalogId=402834815584e463015584e539330016&pnum=1

重定向后Url

http://api.svipmovie.com/front/columns/getVideoList.do?catalogId=402834815584e463015584e539330016&pnum=1

 

说明

在编写代码时时常会有几位同事写接口,一般都是先在同事的本地接口测试。所以接口中的Host就会是同事本地的。可是项目上线时,需要统一改成服务器上的真实Host。如果把接口Host写成工具类改起来还好说,如果没有那就要一个一个的该。OKhttp框架拦截器(Interceptor)重定向就解决了这一问题。

 

 

 

 

 

 

四.拦截器具体使用之 请求体数据加密

既然要对请求体加密,那肯定要知道请求体在哪里,然后才能加密,其实都一样不论是加密url里面的query内容还是加密body体里面的都一样,只要拿到了对应的数据我们想怎么做怎么。

 

 

如上 重定向Url时

package com.wjn.okhttpmvpdemo.mode.Interceptor;

import android.util.Log;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class CustomInterceptor implements Interceptor {

    private String newHost = "://api.svipmovie.com";

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {

        Request request = chain.request();
        HttpUrl url = request.url();

        String scheme = url.scheme();
        String host = url.host();
        String path = url.encodedPath();
        String query = url.encodedQuery();

        Log.d("TAG","原url----:"+url.toString());
        Log.d("TAG","---------------分解原url---------------------");
        Log.d("TAG","scheme----:"+scheme);
        Log.d("TAG","host----:"+host);
        Log.d("TAG","path----:"+path);
        Log.d("TAG","query----:"+query);

        //全部参数Key
        Set<String> collection = url.queryParameterNames();
        Iterator<String> iterable = collection.iterator();
        String key = "";
        while (iterable.hasNext()) {
            key = key + iterable.next() + "###";
        }
        Log.d("TAG","key:"+key);

        //全部参数Value
        Set<String> collections = url.queryParameterNames();
        Iterator<String> iterables = collections.iterator();
        String value = "";
        while (iterables.hasNext()) {
            value = value + url.queryParameter(iterables.next()) + "###";
        }
        Log.d("TAG","value:"+value);

        StringBuffer sb = new StringBuffer();
        String newUrl = sb.append(scheme).append(newHost).append(path).append("?").append(query).toString();
        Log.d("TAG","新url----:"+newUrl);

        Request.Builder builder = request.newBuilder().url(newUrl);
        return chain.proceed(builder.build());
    }
}

 

 

 

既然获取了query也解析出每一个传值的Key Value 就可以将每一个Key对应的Value进行加密。比如

 

catalogId=“加密后的字符串”

 

pnum=“加密后的字符串”

 

新query:catalogId=“加密后的字符串”&pnum=“加密后的字符串”。然后服务器再按照相应的Key得到加密后的Value,然后按照约定的规则解密即可。

 

 

Android 加密详解:

https://blog.csdn.net/weixin_37730482/article/category/8490468

 

 

 

 

 

五.拦截器具体使用之 HEAD动态添加

 

package com.wjn.okhttpmvpdemo.mode.Interceptor;

import com.wjn.okhttpmvpdemo.MyApplication;

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class CustomInterceptors implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {

        String token = MyApplication.getOkhttpCookie();

        Request original = chain.request();
        Request.Builder requestBuilder = original.newBuilder()
                .addHeader("cookie", token);

        Request request = requestBuilder.build();
        return chain.proceed(request);
    }
}

 

 

 

 

 

六.拦截器具体使用之 请求日志抓取

 

<1> 添加Gradle配置

implementation 'io.reactivex:rxjava:1.3.2'
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0' //抓取日志额外添加 

 

 

 

<2> 自定义HttpLog类

package com.wjn.okhttpmvpdemo.mode.Interceptor;

import android.util.Log;

import okhttp3.logging.HttpLoggingInterceptor;

public class HttpLog implements HttpLoggingInterceptor.Logger {
    @Override
    public void log(String message) {
        Log.d("TAG", "message----:"+message);
    }
}

 

 

<3> 添加抓取日志的拦截器

/**
   * 构造方法私有化
*/

private InterceptorRxAndroidOkhttp() {

   Interceptor logInterceptor = new HttpLoggingInterceptor(new HttpLog()).setLevel(HttpLoggingInterceptor.Level.BODY);//抓取日志拦截器对象



    //创建okhttp对象 以及连接,读,取超时时间
    mOkHttpClient = new OkHttpClient.Builder()
             .connectTimeout(DataConstant.nettimeout, TimeUnit.SECONDS)//连接时间
             .readTimeout(DataConstant.nettimeout, TimeUnit.SECONDS)//读时间
             .writeTimeout(DataConstant.nettimeout, TimeUnit.SECONDS)//写时间
             .addInterceptor(logInterceptor)//添加抓取日志的拦截器
             .build();
}

 

 

<4> 效果

message----:--> GET http://api.svipmovie.com/front/columns/getVideoList.do?catalogId=402834815584e463015584e539330016&pnum=1 http/1.1

message----:cookie: KLBRSID=5d3bae4968490d4e7b52d2fd1d9d601b|1555576213|1555576213

message----:--> END GET

message----:<-- 200  http://api.svipmovie.com/front/columns/getVideoList.do?catalogId=402834815584e463015584e539330016&pnum=1 (59ms)

message----:Server: CLOUD ELB 1.0.0

message----:Date: Thu, 18 Apr 2019 08:30:22 GMT

message----:Content-Type: application/json;charset=UTF-8

message----:Transfer-Encoding: chunked

message----:Connection: keep-alive

message----:Vary: Accept-Encoding

message----:Access-Control-Allow-Headers: Content-Type

message----:Access-Control-Allow-Methods: GET,POST,OPTIONS

message----:Access-Control-Allow-Credentials: true

message----:Set-Cookie: KLBRSID=5d3bae4968490d4e7b52d2fd1d9d601b|1555576222|1555576213; Path=/

message----:

 message----:{"msg":"成功","ret":{"adv":{"imgURL":"","dataId":"","htmlURL":"","shareURL":"","title":""},"pnum":1,"totalRecords":14,"bannerList":[],"records":30,"list":[{"airTime":0,"duration":"01:26:06","loadtype":"video","score":0,"angleIcon":"","dataId":"3_e3622954bfd3404d957211028bfb2a71","description":"《动物世界》首映发布会","loadURL":"http://api.svipmovie.com/front/videoDetailApi/videoDetail.do?mediaId=3_e3622954bfd3404d957211028bfb2a71","shareURL":"","pic":"http://phonemovie.ks3-cn-beijing.ksyun.com/image/2018/07/02/1530521662049090886.jpg","title":"《动物世界》首映发布会","roomId":""},{"airTime":0,"duration":"01:24:36","loadtype":"video","score":0,"angleIcon":"","dataId":"3_12ec6b94308a4213b74f8dca13facd91","description":"《幸福马上来》发布会","loadURL":"http://api.svipmovie.com/front/videoDetailApi/videoDetail.do?mediaId=3_12ec6b94308a4213b74f8dca13facd91","shareURL":"","pic":"http://phonemovie.ks3-cn-beijing.ksyun.com/image/2018/07/02/1530521535713073392.jpg","title":"《幸福马上来》发布会","roomId":""},{"airTime":0,"duration":"00:36:18","loadtype":"video","score":0,"angleIcon":"","dataId":"3_7d19f30f6875451b896a158cf9f1092b","description":"《幸福马上来》首映礼红毯","loadURL":"http://api.svipmovie.com/front/videoDetailApi/videoDetail.do?mediaId=3_7d19f30f6875451b896a158cf9f1092b","shareURL":"","pic":"http://phonemovie.ks3-cn-beijing.ksyun.com/image/2018/07/02/1530521497847016506.jpg","title":"《幸福马上来》首映礼红毯","roomId":""},{"airTime":0,"duration":"01:32:54","loadtype":"video","score":0,"angleIcon":"","dataId":"3_1c76a331e4dd46a2b40c76ff7cb0483c","description":"第十届两岸电影展开幕式","loadURL":"http://api.svipmovie.com/front/videoDetailApi/videoDetail.do?mediaId=3_1c76a331e4dd46a2b40c76ff7cb0483c","shareURL":"","pic":"http://phonemovie.ks3-cn-beijing.ksyun.com/image/2018/07/02/1530521210716057912.jpg","title":"第十届两岸电影展开幕式","roomId":""},{"airTime":0,"duration":"01:46:36","loadtype":"video","score":0,"angleIcon":"","dataId":"3_f164502cdbd94889bb82715cd4679250","description":"《江湖儿女》发布会","loadURL":"http://api.svipmovie.com/front/videoDetailApi/videoDetail.do?mediaId=3_f164502cdbd94889bb82715cd4679250","shareURL":"","pic":"http://phonemovie.ks3-cn-beijing.ksyun.com/image/2018/07/02/1530521132032061519.jpg","title":"《江湖儿女》发布会","roomId":""},{"airTime":0,"duration":"01:21:25","loadtype":"video","score":0,"angleIcon":"","dataId":"3_8cfca4605d764ecc92bfda4cde703a91","description":"《超时空同居》发布会","loadURL":"http://api.svipmovie.com/front/videoDetailApi/videoDetail.do?mediaId=3_8cfca4605d764ecc92bfda4cde703a91","shareURL":"","pic":"http://phonemovie.ks3-cn-beijing.ksyun.com/image/2018/05/15/1526378518433029467.jpg","title":"《超时空同居》发布会","roomId":""},{"airTime":0,"duration":"00:28:18","loadtype":"video","score":0,"angleIcon":"","dataId":"3_83365dd74f7840fb9b691bb392bcae14","description":"电影《路过未来》首映礼","loadURL":"http://api.svipmovie.com/front/videoDetailApi/videoDetail.do?mediaId=3_83365dd74f7840fb9b691bb392bcae14","shareURL":"","pic":"http://phonemovie.ks3-cn-beijing.ksyun.com/image/2018/05/15/1526378488136090900.jpg","title":"电影《路过未来》首映礼","roomId":""},{"airTime":0,"duration":"00:42:06","loadtype":"video","score":0,"angleIcon":"","dataId":"3_5bd93420e18c4442853d30d1126d017e","description":"《市长夫人的秘密》首映会","loadURL":"http://api.svipmovie.com/front/videoDetailApi/videoDetail.do?mediaId=3_5bd93420e18c4442853d30d1126d017e","shareURL":"","pic":"http://phonemovie.ks3-cn-beijing.ksyun.com/image/2018/05/15/1526354059484052494.jpg","title":"《市长夫人的秘密》首映会","roomId":""},{"airTime":0,"duration":"00:49:18","loadtype":"video","score":0,"angleIcon":"","dataId":"3_587358b201f4440db10d852ad518585b","description":"电影《泄密者》发布会","loadURL":"http://api.svipmovie.com/front/videoDetailApi/videoDetail.do?mediaId=3_587358b201f4440db10

message----:<-- END HTTP (6608-byte body)

 

 

<5> 注意

 

HttpLoggingInterceptor的日志级别,一共有四个

分别为:NONE  BASIC  HEAD   BODY 

 

(1) NONO:不打印任何日志

 

(2) BASIC:请求行,响应行

    -->请求方式 请求地址 http/1.1 body长度

    <-- 服务器返回状态 地址 时间 长度

 

(3) HEAD:

    请求行,请求头 ,响应行

 

(4) BODY:

    请求行,请求头,请求体,响应行,响应体,

由上可以看出BODY级别是最全的

 

 

 

附:Interceptor GitHub链接

https://github.com/square/okhttp/wiki/Interceptors

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值