OKhttp * 实现实践环节源码解析

作者:itbird01 时间:2023-04-27 05:00:21 

本节我们开始自我实现我们自己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;
   }
}

运行一下

OKhttp * 实现实践环节源码解析

题外话

说到责任链模式,这里有一个题外话,我们之前分析view事件源码的时候,也看到过,view 事件源码,也是责任链机制,它是通过每层返回true、false来决定是否拦截。

OKhttp * 实现实践环节源码解析

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

来源:https://juejin.cn/post/7181992810667573306

标签:OKhttp, , ,实践
0
投稿

猜你喜欢

  • java语言基础之标识符和命名规则详解

    2023-04-21 16:50:18
  • Java实战之用springboot+netty实现简单的一对一聊天

    2023-12-03 07:28:19
  • Android PickerScrollView滑动选择控件使用方法详解

    2023-06-19 01:00:34
  • java原生序列化和Kryo序列化性能实例对比分析

    2023-11-26 16:04:20
  • android自定义控件实现简易时间轴(2)

    2021-10-03 06:52:39
  • Java游戏开发拼图游戏经典版

    2023-10-10 16:23:08
  • springboot 多数据源的实现(最简单的整合方式)

    2022-08-20 02:30:11
  • c#动态编译执行对象方法示例 运用映射机制创建对象

    2023-11-19 22:39:32
  • 微服务架构设计RocketMQ基础及环境整合

    2023-02-18 17:18:15
  • C#开发微信门户及应用(5) 用户分组信息管理

    2022-08-03 04:52:20
  • WinForm调用jar包的方法分析

    2023-11-17 04:09:46
  • C语言 socketpair用法案例讲解

    2022-07-24 12:41:48
  • android多种滑动冲突的解决方案

    2021-11-16 11:20:10
  • 使用位运算实现网页中的过滤、筛选功能实例

    2023-06-04 10:00:31
  • Spring Cloud项目前后端分离跨域的操作

    2022-05-20 08:11:16
  • android端使用openCV实现车牌检测

    2023-02-26 07:50:50
  • Android token过期刷新处理的方法示例

    2023-11-23 14:11:40
  • Java反转数组输出实例代码

    2023-09-04 22:18:48
  • Spring Security中的Servlet过滤器体系代码分析

    2023-03-23 19:05:34
  • SpringBoot整合activemq的案例代码

    2023-11-06 18:41:37
  • asp之家 软件编程 m.aspxhome.com