文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-01-05 12:02

关注

正文

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

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

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

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

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

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

拦截器的自我实现

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

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;

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;

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;

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;

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;

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;

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 事件源码,也是责任链机制,它是通过每层返回true、false来决定是否拦截。

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

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

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯