首页 > 其他分享 >OkHttp发送请求流程

OkHttp发送请求流程

时间:2023-07-24 20:31:36浏览次数:38  
标签:boolean 流程 private public 发送 client OkHttp new final

OkHttp发送请求流程

Request

主要包含5个属性,涵盖请求的基本信息:url method headers body tags

public final class Request {
  final HttpUrl url;
  final String method;
  final Headers headers;
  final @Nullable RequestBody body;
  final Map<Class<?>, Object> tags;

  private volatile @Nullable CacheControl cacheControl; // Lazily initialized.

  Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tags = Util.immutableMap(builder.tags);
  }
  // 忽略代码
  // 内部静态构造类 Builder  
    
}

内部静态构造类 Builder

public static class Builder {
    @Nullable HttpUrl url;
    String method;
    Headers.Builder headers;
    @Nullable RequestBody body;

    /** A mutable map of tags, or an immutable empty map if we don't have any. */
    Map<Class<?>, Object> tags = Collections.emptyMap();

    public Builder() {
      this.method = "GET";
      this.headers = new Headers.Builder();
    }

    Builder(Request request) {
      this.url = request.url;
      this.method = request.method;
      this.body = request.body;
      this.tags = request.tags.isEmpty()
          ? Collections.emptyMap()
          : new LinkedHashMap<>(request.tags);
      this.headers = request.headers.newBuilder();
    }

    // 忽略
    // 构造出request  
    public Request build() {
      if (url == null) throw new IllegalStateException("url == null");
      return new Request(this);
    }
  }

使用构造者模式,将用户请求信息封装为一个Request

public static Request createPostRequest(String url, Object body, Map<String, String> headers) {
    Request.Builder builder = new Request.Builder()
            .post(RequestBody.create(MediaType.parse(JSON_CONTENT_TYPE), JSONUtil.serialize(body).getBytes(UTF_8)))
            .url(url).headers(createHeader(headers));
    return builder.build();
}

OkHttpClient

建立连接发送请求的客户端,包含连接参数:协议、TLS版本、超时时间,以及框架提供的过滤器、监听器、dns、证书等..

public class OkHttpClient implements Cloneable, Call.Factory, WebSocket.Factory {
  static final List<Protocol> DEFAULT_PROTOCOLS = Util.immutableList(
      Protocol.HTTP_2, Protocol.HTTP_1_1);

  static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS = Util.immutableList(
      ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT);

  static {
    Internal.instance = new Internal() {
      @Override public void addLenient(Headers.Builder builder, String line) {
        builder.addLenient(line);
      }

      @Override public void addLenient(Headers.Builder builder, String name, String value) {
        builder.addLenient(name, value);
      }

      @Override public RealConnectionPool realConnectionPool(ConnectionPool connectionPool) {
        return connectionPool.delegate;
      }

      @Override public boolean equalsNonHost(Address a, Address b) {
        return a.equalsNonHost(b);
      }

      @Override public int code(Response.Builder responseBuilder) {
        return responseBuilder.code;
      }

      @Override
      public void apply(ConnectionSpec tlsConfiguration, SSLSocket sslSocket, boolean isFallback) {
        tlsConfiguration.apply(sslSocket, isFallback);
      }

      @Override public Call newWebSocketCall(OkHttpClient client, Request originalRequest) {
        return RealCall.newRealCall(client, originalRequest, true);
      }

      @Override public void initExchange(
          Response.Builder responseBuilder, Exchange exchange) {
        responseBuilder.initExchange(exchange);
      }

      @Override public @Nullable Exchange exchange(Response response) {
        return response.exchange;
      }
    };
  }

  final Dispatcher dispatcher;
  final @Nullable Proxy proxy;
  final List<Protocol> protocols;
  final List<ConnectionSpec> connectionSpecs;
  final List<Interceptor> interceptors;
  final List<Interceptor> networkInterceptors;
  final EventListener.Factory eventListenerFactory;
  final ProxySelector proxySelector;
  final CookieJar cookieJar;
  final @Nullable Cache cache;
  final @Nullable InternalCache internalCache;
  final SocketFactory socketFactory;
  final SSLSocketFactory sslSocketFactory;
  final CertificateChainCleaner certificateChainCleaner;
  final HostnameVerifier hostnameVerifier;
  final CertificatePinner certificatePinner;
  final Authenticator proxyAuthenticator;
  final Authenticator authenticator;
  final ConnectionPool connectionPool;
  final Dns dns;
  final boolean followSslRedirects;
  final boolean followRedirects;
  final boolean retryOnConnectionFailure;
  final int callTimeout;
  final int connectTimeout;
  final int readTimeout;
  final int writeTimeout;
  final int pingInterval;

  public OkHttpClient() {
    this(new Builder());
  }
  
/**
 * Prepares the {@code request} to be executed at some point in the future.
 */
@Override public Call newCall(Request request) {
  return RealCall.newRealCall(this, request, false /* for web socket */);
}

/**
 * Uses {@code request} to connect a new web socket.
 */
@Override public WebSocket newWebSocket(Request request, WebSocketListener listener) {
  RealWebSocket webSocket = new RealWebSocket(request, listener, new Random(), pingInterval);
  webSocket.connect(this);
  return webSocket;
}

public Builder newBuilder() {
  return new Builder(this);
}

同样是使用构造者模式创建,其内部构造类就不赘述了

ConnectionPool pool = new ConnectionPool(5, 10, TimeUnit.MINUTES);
client = new OkHttpClient().newBuilder()
        .connectTimeout(15, TimeUnit.SECONDS)
        .readTimeout(60, TimeUnit.SECONDS)
        .connectionPool(pool)
        .build();

RealCall

A call is a request that has been prepared for execution. A call can be canceled. As this object represents a single request/response pair (stream), it cannot be executed twice.

call是已准备好执行的请求。可以取消呼叫。由于该对象表示单个请求/响应对(流),因此不能执行两次.

理解为一通电话,就是一次请求。

顶级接口Call的唯一实现类,httpclient实现了Call.Factory方法,所以可以通过httpclient实例创建call。

@Override public Call newCall(Request request) {
  return RealCall.newRealCall(this, request, false /* for web socket */);
}

static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
  // Safely publish the Call instance to the EventListener.
  RealCall call = new RealCall(client, originalRequest, forWebSocket);
  call.transmitter = new Transmitter(client, call);
  return call;
}
final class RealCall implements Call {
  final OkHttpClient client;
  
  // 和Call之间存在循环依赖,从上面Call的创建可以看出,Transmitter在Call创建之后创建
  private Transmitter transmitter;

  /** The application's original request unadulterated by redirects or auth headers. */
  final Request originalRequest;
  final boolean forWebSocket;

  // 防止执行两次
  private boolean executed;

  private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
  }

  static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    // Safely publish the Call instance to the EventListener.
    RealCall call = new RealCall(client, originalRequest, forWebSocket);
    call.transmitter = new Transmitter(client, call);
    return call;
  }

  // 重点
  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.timeoutEnter();
    transmitter.callStart();
    try {
      client.dispatcher().executed(this);
      return getResponseWithInterceptorChain();
    } finally {
      client.dispatcher().finished(this);
    }
  }

  @Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    transmitter.callStart();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

    /**
     * Attempt to enqueue this async call on {@code executorService}. This will attempt to clean up
     * if the executor has been shut down by reporting the call as failed.
     */
    void executeOn(ExecutorService executorService) {
      assert (!Thread.holdsLock(client.dispatcher()));
      boolean success = false;
      try {
        executorService.execute(this);
        success = true;
      } catch (RejectedExecutionException e) {
        InterruptedIOException ioException = new InterruptedIOException("executor rejected");
        ioException.initCause(e);
        transmitter.noMoreExchanges(ioException);
        responseCallback.onFailure(RealCall.this, ioException);
      } finally {
        if (!success) {
          client.dispatcher().finished(this); // This call is no longer running!
        }
      }
    }

    @Override protected void execute() {
      boolean signalledCallback = false;
      transmitter.timeoutEnter();
      try {
        Response response = getResponseWithInterceptorChain();
        signalledCallback = true;
        responseCallback.onResponse(RealCall.this, response);
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

  // 重点
  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(new RetryAndFollowUpInterceptor(client));
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
        originalRequest, this, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    boolean calledNoMoreExchanges = false;
    try {
      Response response = chain.proceed(originalRequest);
      if (transmitter.isCanceled()) {
        closeQuietly(response);
        throw new IOException("Canceled");
      }
      return response;
    } catch (IOException e) {
      calledNoMoreExchanges = true;
      throw transmitter.noMoreExchanges(e);
    } finally {
      if (!calledNoMoreExchanges) {
        transmitter.noMoreExchanges(null);
      }
    }
  }
}

Transmitter

Bridge between OkHttp's application and network layers. This class exposes high-level application layer primitives: connections, requests, responses, and streams.

应用层和网络层之间的桥梁,抽象了connections, requests, responses, and streams.

他就是一个人,发短信这个角色

public final class Transmitter {
  private final OkHttpClient client;
  private final RealConnectionPool connectionPool;
  private final Call call;
  private final EventListener eventListener;
  private final AsyncTimeout timeout = new AsyncTimeout() {
    @Override protected void timedOut() {
      cancel();
    }
  };

  private @Nullable Object callStackTrace;

  private Request request;
  private ExchangeFinder exchangeFinder;

  // Guarded by connectionPool.
  public RealConnection connection;
  private @Nullable Exchange exchange;
  private boolean exchangeRequestDone;
  private boolean exchangeResponseDone;
  private boolean canceled;
  private boolean timeoutEarlyExit;
  private boolean noMoreExchanges;

  public Transmitter(OkHttpClient client, Call call) {
    this.client = client;
    this.connectionPool = Internal.instance.realConnectionPool(client.connectionPool());
    this.call = call;
    this.eventListener = client.eventListenerFactory().create(call);
    this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
  }
  
  //忽略部分代码
}

Dispatcher

请求调度,异步请求的话使用所指定的excutorService来执行请求

public final class Dispatcher {
  // 限制并发请求的最大个数
  private int maxRequests = 64;
  // 限制每个host并发请求的个数
  private int maxRequestsPerHost = 5;
  private @Nullable Runnable idleCallback;

  /** Executes calls. Created lazily. */
  private @Nullable ExecutorService executorService;

  /** Ready async calls in the order they'll be run. */
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

  public Dispatcher() {
  }

  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }
  
  private boolean promoteAndExecute() {
  assert (!Thread.holdsLock(this));

  List<AsyncCall> executableCalls = new ArrayList<>();
  boolean isRunning;
  synchronized (this) {
    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall asyncCall = i.next();

      if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
      if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.

      i.remove();
      asyncCall.callsPerHost().incrementAndGet();
      executableCalls.add(asyncCall);
      runningAsyncCalls.add(asyncCall);
    }
    isRunning = runningCallsCount() > 0;
  }

  for (int i = 0, size = executableCalls.size(); i < size; i++) {
    AsyncCall asyncCall = executableCalls.get(i);
    asyncCall.executeOn(executorService());
  }

  return isRunning;
}
// 忽略部分代码
}

Okhttp超时时间

  • 连接超时

三次握手 + SSL建立耗时

超时时间:默认10s

测试方法:请求 www.facebook.com 触发 SocketTimeoutException

  • 读取超时

连接建立后,从远端获取数据。TCP 传输

  • 写入超时

连接建立后,向远端发送数据。TCP 传输

  • 总超时

从发起到结束的总时长。其中不包括 UnknownHostException 情况

设置超时时间

okhttp3.OkHttpClient.Builder clientBuilder = new okhttp3.OkHttpClient.Builder();
    //读取超时
    clientBuilder.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
    //连接超时
    clientBuilder.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
    //写入超时
    clientBuilder.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
    //总超时时间
    clientBuilder.callTimeout(CALL_TIMEOUT, TimeUnit.SECONDS);

连接池 ConnectionPool

为什么需要连接池?

在okhttp中,服务器与客户端的http连接被抽象为一个个Connection,如果每个请求都新建一个连接,创建销毁连接是一个比较大的消耗,okhttp就提供了ConnectionPool来管理连接,不马上销毁,在使用相同连接的请求打来的时候复用连接

复用的粒度是怎么样的?

有没有使用多个连接减轻负担的说法?

实现原理?

如何快速使用?

标签:boolean,流程,private,public,发送,client,OkHttp,new,final
From: https://blog.51cto.com/u_16167766/6838910

相关文章

  • 【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析
    Redis基本概念Redis(REmoteDIctionaryServer)是由SalvatoreSanfilippo开发的高性能key-value存储系统,完全遵守BSD协议并且开源免费。Redis特点说明Redis具有以下几个特点,使其与其他key-value缓存产品(如memcache)相区别。数据持久化:Redis支持将内存中的数据保存到磁盘中,以便在重新......
  • Linux 网络收包流程
    哈喽大家好,我是咸鱼我们在跟别人网上聊天的时候,有没有想过你发送的信息是怎么传到对方的电脑上的又或者我们在上网冲浪的时候,有没有想过HTML页面是怎么显示在我们的电脑屏幕上的无论是我们跟别人聊天还是上网冲浪,其实都依靠于计算机网络这项技术计算机网络是指将多台计算机......
  • 摆脱效率低的办公,可以了解流程表单设计器
    目前,低效率的办公已经无法满足市场需求。那么,怎么样才能实现高效率办公?通过什么样的平台提质增效?低代码开发平台是目前在现代化办公环境中较为流行的平台,其中的流程表单设计器易操作、灵活、便捷,深得广大用户的青睐和喜欢。今天,我们一起来了解低代码开发平台以及流程表单设计器的......
  • Web流程图绘制使用raphael
    摘要:本文要实现一个流程图的绘制,最终的目标是实现流程图的自动绘制,并可进行操作,直接点击流程图上对应的方框就可以让后台跑相应的程序。一、插件介绍1、图形绘制raphael其中图形绘制使用了raphael,下载地址:http://raphaeljs.com,它的功能非常强大。其中有一些DEMO如下:Web流程图......
  • 如何在Spring Boot中记录用户系统操作流程?
    在现代Web应用程序中,记录用户系统操作流程对于监控用户行为、进行故障排查、安全审计等方面都是非常重要的。在本篇博客中,我们将介绍如何在SpringBoot中使用AOP(面向切面编程)和日志框架来实现用户系统操作流程的记录。1.介绍在大多数Web应用程序中,需要记录用户在系统中的操......
  • 德州申请iso的条件和流程是什么
    德州申请iso的条件和流程是什么恒标知产刘经理15266872201 办理ISO需要的基本条件 向认证公司提供以下资料即可: 做ISO9001质量管理体系认证需要准备的材料如下: 1、企业营业执照副本以及组织机构代码证的复印件; 2、企业计量及检测设备的检定报告; 3、特殊岗位的上岗证 ; 4、......
  • .net core razor发送邮件模板
    .NETCoreRazor发送邮件模板实现步骤概述在本文中,我将指导你如何在.NETCoreRazor项目中实现发送邮件模板。我们将使用.NETCore的SmtpClient类和Razor模板引擎来创建和发送包含动态内容的电子邮件。步骤步骤描述1引入必要的命名空间2创建Razor视图和模型3......
  • activit中的子流程
    子流程是一种特殊的流程活动,它可以包含其他的流程元素,它是一个较大的流程组成部分。一、嵌入子流程整个子流程会被完整的定义在父流程中。二、调用子流程存在多个流程共用的子流程,就可以把这个子流程单独抽取成一个文件,在其他流程定义文件中可以引用这个子流程。三、事件子......
  • U-boot引导内核流程分析
    原文地址:https://blog.csdn.net/qq_28992301/article/details/51873201U-boot引导内核流程分析1.加载内核当U-boot完成重定位和初始化外设后,它将正式进入工作状态,可以加载内核镜像到DDR的链接地址中了,具体的地址也可以通过bootcmd这个环境变量来指定,内核镜像有两种加载方式:......
  • git的版本控制流程
    1、git是一款版本控制工具例如我们常用的淘宝,每次升级,版本号就会加一。那么我们怎么控制版本号呢?--使用git。 2、最常使用的git指令gitadd.暂存gitcommit-m"***"提交到本地gitpull将远程仓库代码下拉到本地gitpush提交到远程仓库不建议使用【GitBash】中......