Android:OKhttp拦截器整理笔记

news2025/1/12 21:00:07

目录

正文

拦截器的自我实现

RetryAndFollowUpInterceptor

BridgeInterceptor

CacheInterceptor

ConnectInterceptor

CallServerInterceptor

运行一下

题外话


OkHttp是一个高效的HTTP库:

支持HTTP/2, HTTP/2通过使用多路复用技术在一个单独的TCP连接上支持并发, 通过在一个连接上一次性发送多个请求来发送或接收数据
如果HTTP/2不可用, 连接池复用技术也可以极大减少延时
支持GZIP, 可以压缩下载体积
响应缓存可以直接避免重复请求
会从很多常用的连接问题中自动恢复
如果您的服务器配置了多个IP地址, 当第一个IP连接失败的时候, OkHttp会自动尝试下一个IP OkHttp还处理了代理服务器问题和SSL握手失败问题
优势

使用 OkHttp无需重写您程序中的网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的API。如果您用了 Apache HttpClient,则OkHttp也提供了一个对应的okhttp-apache 模块
 

正文

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

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

  • RetryAndFollowUpInterceptor:重试拦截器

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

  • BridgeInterceptor:基础的拦截器

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

  • CacheInterceptor:缓存拦截器

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

  • ConnectInterceptor:连接的拦截器

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

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

拦截器的自我实现

好了,接下来,把我们之前写的框架的代码,重新梳理一下,新增一下几个拦截器。 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;
/**
 * 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 事件源码,也是责任链机制,它是通过每层返回true、false来决定是否拦截。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/145812.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Referer与XMLHttpRequest整理

Apache日志分割 1.原因 1.随着网络的访问量的增加&#xff0c;默认情况下Apache的单个日志文件也会越来越大。 2.日志文件占用磁盘空间很大 3.查看相关信息不方便2.对日志文件进行分割 1.Apache自带rotatelogs分割工具实现 2.第三方工具cronolog 分割3.配置日志分割(我用的p…

基于springboot+mybatis-plus+mysql+python+tensorflow2.0波导识别管理系统

基于springbootmybatis-plusmysqlpythontensorflow2.0波导识别管理系统一、系统介绍二、功能展示1.图片上传2.波导识别三、代码展示四、其它系统五、获取源码一、系统介绍 技术框架&#xff1a; 前端&#xff1a;vue 后端&#xff1a;springboot 算法&#xff1a;pythontensor…

用八叉树优化RayCasting

在之前的文章中&#xff0c;我们不得不等待 8 分钟来渲染一盏精灵灯和一个球体。 总而言之&#xff0c;我们询问每个像素是否有多个三角形之一相交。 这个场景包括&#xff1a; 4 个物体&#xff1a;1 个灯、2 个球体和 1 个平面34,378 个三角形&#xff1a;1 个球体没有三角形…

某音漂亮小姐姐视频合集一键下载,想看就看!

大家好&#xff0c;我是派森酱&#xff01; 最近工作压力大&#xff0c;每天晚上回来基本洗洗就要睡了。但是总觉得一天就这么过去&#xff0c;有点遗憾&#xff0c;所以每天睡前躺床上刷刷抖音&#xff0c;看看美丽小姐姐&#xff0c;心情就会舒畅许多&#xff01; 有些小姐姐…

架构师成长日记 - 01 4+1视图模型

文章目录 什么是软件架构什么是架构师?架构师的主要能力4+1视图模型逻辑视图(Logical View)开发视图(Development View)物理视图(Physical View)过程视图(Process View)场景视图(scenarios)软件建模语言什么是软件架构 软件架构是有关软件整体结构与组件的抽象描述,用于指导大…

StarkWare的Recursive STARKs

1. 引言 StarkWare的Recursive STARKs 为首个在以太坊主网上线的&#xff0c;针对通用计算的recursive stark proof方案&#xff1a; 递归证明目前已在以太坊主网上线&#xff1a; 扩容StarkEx app扩容StarkNet用于StarkWare的SaaS scaling engine用于permissionless rollup …

javaScript浅谈----asyncawait

什么是 async &#xff1f; async/await 是 ES7 的标准&#xff0c;Promise 是 ES6 标准&#xff0c;async/await 这套 API 也是用来帮助我们写异步代码的&#xff0c;它是构建在 Promise 之上的。 async的特点&#xff1a; async 一般不单独使用&#xff0c;而是和 await 一…

3. 无重复字符的最长子串(滑动窗口)

文章目录题目描述暴力破解滑动窗口优化知识积累待解决题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示例 2: 输…

python 操作符介绍

python操作符分类&#xff1a;算数操作符&#xff1b;比较操作符&#xff1b;逻辑操作符&#xff1b;成员操作符&#xff1b;身份操作符&#xff1b; 1 算数操作符&#xff1a; 常用的算数操作符&#xff1a;; python如何执行除法&#xff1a; 许多编程语言中整数除法执行的…

另一半人马座,孟庭苇

我写过生于12月25日的半人马座桂纶镁《半人马座&#xff0c;桂纶镁》。射手座是11月23日-12月21日。而摩羯座的开始恰恰是&#xff1a;12月22日。而孟庭苇&#xff0c;恰恰就生于12月22日。她更是半人马座啊。1989年&#xff0c;20岁的孟庭苇出演铃木机车广告出道&#xff08;没…

分享一套响应式自适应公司网站官网源码,带文字搭建教程

分享一套响应式自适应公司网站官网源码&#xff0c;带文字搭建教程。需要源码学习可私信我。 技术架构 PHP7.2 nginx mysql5.7 JS CSS HTML cnetos7以上 宝塔面板 系统介绍 1、四网合一企业网站管理系统支持在线升级&#xff08;支持跨版本&#xff09;、插件在线安装、系…

跳表SkipList介绍与实现

目录 一.跳表介绍 二.实现思路 &#xff08;一&#xff09;.结点结构 &#xff08;二&#xff09;.检索 &#xff08;三&#xff09;.插入 &#xff08;四&#xff09;.删除 三.实现代码 一.跳表介绍 跳表是一种随机化数据结构&#xff0c;主要用于快速检索数据。实质上…

JavaScript 函数

文章目录JavaScript 函数JavaScript 函数语法调用带参数的函数带有返回值的函数局部 JavaScript 变量全局 JavaScript 变量JavaScript 变量的生存期向未声明的 JavaScript 变量分配值笔记列表JavaScript 函数 函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。 实…

Go语言之容器总结

目录 1.值类型 1.1. 数组Array 数组遍历 数组初始化 值拷贝 内置函数len、cap 2. 引用数据类型 2.1. 切片slice 切片初始化 切片的内存布局 通过slice修改struct array值 用append内置函数操作切片&#xff08;切片追加&#xff09; slice自动扩容 slice中cap重新…

基于yolov5算法的安全帽头盔检测源码+模型,Pytorch开发,智能工地安全领域中头盔目标检测的应用

基于yolov5算法的安全帽头盔检测|Pytorch开发源码模型 本期给大家打开的是YOLOv5在智能工地安全领域中头盔目标检测的应用。 完整代码下载地址&#xff1a;基于yolov5算法的安全帽头盔检测源码模型 可视化界面演示&#xff1a; &#x1f4a5;&#x1f4a5;&#x1f4a5;新增…

opencv c++ Mat CUDA的编译与使用

Mat 构造函数 cv::Mat img ; //默认 定义了一个Mat img cv::imread("image.jpg");//除了直接读取&#xff0c;还有通过大小构造等cv::Mat img cv::imread("image.png", IMREAD_GRAYSCALE); cv::Mat img_novel img;转换 Mat::convertTo(Mat& m, in…

【自学Java】Java方法

Java方法 Java方法教程 在 Java 语言 中&#xff0c;方法就是一段可重复调用的代码段。在平时开发直接交流中&#xff0c;也有一些同学喜欢把方法叫做函数&#xff0c;这两个其实是一个概念。 Java语言方法详解 语法 public void fun(Object param1,...){//do something }…

多线程与高并发(四)

【Exchanger】&#xff1a; package Ten_Class.t04.no139;import java.util.concurrent.Exchanger;public class T12_TestExchanger {static Exchanger<String> exchanger new Exchanger<>();public static void main(String[] args) {new Thread(() -> {Stri…

实验二十四 策略路由配置

实验二十四 策略路由配置实验要求&#xff1a; 某企业通过路由器AR1连接互联网&#xff0c;由于业务儒要&#xff0c;与两家运营商ISPA和ISPB相连。 企业网内的数据流从业务类型上可以分为两类&#xff0c; 一类来自于网络172.16.0.0/16&#xff0c;另 一类 来自于网络172.17.0…

百趣代谢组学分享:黑木耳多糖对小鼠肠道微生物及代谢表型的影响

文章标题&#xff1a;Effects of Auricularia auricula Polysaccharides on Gut Microbiota and Metabolic Phenotype in Mice 发表期刊&#xff1a;Foods 影响因子&#xff1a;5.561 作者单位&#xff1a;西北大学 百趣提供服务&#xff1a;发现代谢组学Standard-亲水版、1…