OKhttp拦截器实现实践环节源码解析

2023-01-06 11:14:57
目录
正文拦截器的自我实现RetryAndFollowUpInterceptorBridgeInterceptorCacheInterceptorConnectInterceptorCallServerInterceptor运行一下题外话

正文

本节我们开始自我实现我们自己okhttp框架中的每个拦截器。

先简单回顾一下各个拦截器的作用:

    RetryAndFollowUpInterceptor:重试拦截器

    处理重试的一个拦截器,会去处理一些异常,根据底层返回的响应数据,先进行一些特殊状态码的判断,例如:如果底层返回307,则根据服务端返回的最新location,重新构建新的请求,交由底层拦截器,重新发起请求。如果底层返回路由异常、某些IO异常,则会continue,重新发起请求。

      BridgeInterceptor:基础的拦截器

      给我们平常发起的请求,添加通用和请求首部信息,做一个简单的处理,设置一些通用的请求头,Cookie、Connection、Content-Type、Content-Length,做一些返回的处理,如果返回的数据被压缩了,采用>

        CacheInterceptor:缓存拦截器

        缓存存储策略、缓存过期策略、缓存对比策略的具体实现。

          ConnectInterceptor:连接的拦截器

          ConnectInterceptor负责连接复用、建立socket连接,okio与socket输入输出流绑定。

            CallServerInterceptor: 具体与服务器通信,给服务器写数据和读取数据;

            拦截器的自我实现

            好了,接下来,把我们之前写的框架的代码,重新梳理一下,新增一下几个拦截器。>

            package com.itbird.okhttpstudy.okhttp;
            import android.util.Log;
            import com.itbird.okhttpstudy.interceptor.BridgeInterceptor;
            import com.itbird.okhttpstudy.interceptor.CacheInterceptor;
            import com.itbird.okhttpstudy.interceptor.CallServerInterceptor;
            import com.itbird.okhttpstudy.interceptor.ConnectInterceptor;
            import com.itbird.okhttpstudy.interceptor.Interceptor;
            import com.itbird.okhttpstudy.interceptor.RetryAndFollowUpInterceptor;
            import java.io.IOException;
            import java.util.ArrayList;
            import java.util.List;
            /**
             * Created by itbird on 2022/11/21
             */
            public class RealCall implements Call {
                private Request request;
                private OkhttpClient okhttpClient;
                public RealCall(Request request, OkhttpClient okhttpClient) {
                    this.request = request;
                    this.okhttpClient = okhttpClient;
                }
                @Override
                public void enqueue(Callback callback) {
                    okhttpClient.dispatcher().enqueue(new AsyncCall(callback));
                }
                @Override
                public Response execute() {
                    return getResponseWithInterceptorChain();
                }
                @Override
                public Request request() {
                    return request;
                }
                private Response getResponseWithInterceptorChain() {
                    List<Interceptor> interceptors = new ArrayList<Interceptor>();
                    interceptors.add(new BridgeInterceptor());// 基础
                    interceptors.add(new CacheInterceptor());// 缓存
                    interceptors.add(new ConnectInterceptor());// 建立连接
                    interceptors.add(new CallServerInterceptor());// 写数据
                    interceptors.add(new RetryAndFollowUpInterceptor());// 重试
                    Interceptor.Chain chain = new RealInterceptorChain(this, interceptors, request);
                    try {
                        return chain.proceed(request);
                    } catch (IOException e) {
                        //处理过程被中断时,通过错误码返回
                        return null;
                    }
                }
                class AsyncCall extends NamedRunnable {
                    private Callback callback;
                    public AsyncCall(Callback callback) {
                        this.callback = callback;
                    }
                    @Override
                    public void execute() {
                        Log.d(Constants.TAG, "AsyncCall execute");
                        //这里有问题的
                        Response response = getResponseWithInterceptorChain();
                        if (callback != null) {
                            try {
                                callback.onResponse(RealCall.this, response);
                            } catch (IOException e) {
                            }
                        }
                    }
                }
            }
            

            接下来还是老办法,按照AS提示,新建这些类。

            RetryAndFollowUpInterceptor

            package com.itbird.okhttpstudy.interceptor;
            import android.util.Log;
            import com.itbird.okhttpstudy.okhttp.Constants;
            import com.itbird.okhttpstudy.okhttp.Request;
            import com.itbird.okhttpstudy.okhttp.Response;
            import java.io.IOException;
            /**
             * Created by itbird on 2022/11/24
             */
            public class RetryAndFollowUpInterceptor implements Interceptor {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Log.d(Constants.TAG, "RetryAndFollowUpInterceptor");
                    Request request = chain.request();
                    //okhttp表现为,此处,去根据底层抛出的异常,决定是否为关键错误异常,如果不是,则while true循环,去执行重试请求
                    return chain.proceed(request);
                }
            }
            

            BridgeInterceptor

            package com.itbird.okhttpstudy.interceptor;
            import android.util.Log;
            import com.itbird.okhttpstudy.okhttp.Constants;
            import com.itbird.okhttpstudy.okhttp.Request;
            import com.itbird.okhttpstudy.okhttp.RequsetBody;
            import com.itbird.okhttpstudy.okhttp.Response;
            import java.io.IOException;
            /**
             * Created by itbird on 2022/11/24
             */
            public class BridgeInterceptor implements Interceptor {
                public BridgeInterceptor() {
                }
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Log.d(Constants.TAG, "BridgeInterceptor");
                    Request request = chain.request();
                    // 添加一些请求头
            //        request.addParam("Connection", "keep-alive");
                    // 做一些其他处理
                    if (request.requsetBody() != null) {
                        RequsetBody requestBody = request.requsetBody();
                        request.addParam("Content-Type", requestBody.getContentType());
                        request.addParam("Content-Length", Long.toString(requestBody.getContentLength()));
                    }
                    //GZIP数据流转换
                    return chain.proceed(request);
                }
            }
            

            CacheInterceptor

            package com.itbird.okhttpstudy.interceptor;
            import android.util.Log;
            import com.itbird.okhttpstudy.okhttp.CacheControl;
            import com.itbird.okhttpstudy.okhttp.Constants;
            import com.itbird.okhttpstudy.okhttp.Request;
            import com.itbird.okhttpstudy.okhttp.Response;
            import java.io.IOException;
            /**
             * Created by itbird on 2022/11/24
             */
            public class CacheInterceptor implements Interceptor {
                public CacheInterceptor() {
                }
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Log.d(Constants.TAG, "CacheInterceptor");
                    Request request = chain.request();
                    if (request.cache() == CacheControl.FORCE_CACHE) {
                        //本地缓存有没有,缓存过期了没有,缓存对比服务器返回307
                    }
                    return chain.proceed(request);
                }
            }
            

            ConnectInterceptor

            package com.itbird.okhttpstudy.interceptor;
            import android.util.Log;
            import com.itbird.okhttpstudy.okhttp.Constants;
            import com.itbird.okhttpstudy.okhttp.Request;
            import com.itbird.okhttpstudy.okhttp.Response;
            import java.io.IOException;
            /**
             * Created by itbird on 2022/11/24
             */
            public class ConnectInterceptor implements Interceptor {
                public ConnectInterceptor() {
                }
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Log.d(Constants.TAG, "ConnectInterceptor");
                    Request request = chain.request();
                    //表现为okhttp的话,这里就是socket简历连接,并且将socket输入输出流与okio绑定在一起
                    return chain.proceed(request);
                }
            }
            

            CallServerInterceptor

            package com.itbird.okhttpstudy.interceptor;
            import android.util.Log;
            import com.itbird.okhttpstudy.okhttp.Constants;
            import com.itbird.okhttpstudy.okhttp.Request;
            import com.itbird.okhttpstudy.okhttp.Response;
            import java.io.IOException;
            import java.io.InputStream;
            import java.net.HttpURLConnection;
            import java.net.MalformedURLException;
            import java.net.URL;
            /**
             * Created by itbird on 2022/11/24
             */
            public class CallServerInterceptor implements Interceptor {
                public CallServerInterceptor() {
                }
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Log.d(Constants.TAG, "CallServerInterceptor");
                    Request request = chain.request();
                    try {
                        //获取连接请求
                        URL url = new URL(request.url());
                        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                        //设置连接超时
                        httpURLConnection.setConnectTimeout(3000);
                        //设置方法
                        httpURLConnection.setRequestMethod(request.method());
                        if (request.requsetBody() != null) {
                            httpURLConnection.setRequestProperty("Content-Type", request.requsetBody().getContentType());
                            httpURLConnection.setRequestProperty("Content-Length", String.valueOf(request.requsetBody().getContentLength()));
                            Log.d(Constants.TAG, httpURLConnection.getRequestProperty("Content-Length"));
                            Log.d(Constants.TAG, httpURLConnection.getRequestProperty("Content-Type"));
                        }
                        //开始连接
                        httpURLConnection.connect();
                        //插入,如果requsetbody不为空,则继续写入内容
                        if (request.requsetBody() != null) {
                            request.requsetBody().writeBodyData(httpURLConnection.getOutputStream());
                        }
                        //判断返回的状态码
                        if (httpURLConnection.getResponseCode() == 200) {
                            //获取返回的数据
                            InputStream inputStream = httpURLConnection.getInputStream();
                            //将返回的数据,封装为response
                            Response response = new Response(inputStream);
                            return response;
                        }
                    } catch (MalformedURLException e) {
                        throw e;
                    } catch (IOException e) {
                        throw e;
                    }
                    return null;
                }
            }
            

            运行一下

            题外话

            说到责任链模式,这里有一个题外话,我们之前分析view事件源码的时候,也看到过,view>

            大家想一下,和okhttp这里的责任链有啥不同的?我们上面查看okhttp源码的时候知道,它并不是通过每层返回true or false来决定是否拦截的,而是根据每层返回的response 以及 是否抛出异常来决定是否拦截。

            以上就是OKhttp拦截器实现实践环节源码解析的详细内容,更多关于OKhttp 拦截器实现的资料请关注易采站长站其它相关文章!