OKHttp源码解析

Android为我们提供了两种HTTP交互的方式:HttpURLConnection 和 Apache HTTP Client,虽然两者都支持HTTPS,流的上传和下载,配置超时,IPv6和连接池,已足够满足我们各种HTTP请求的需求。但更高效的使用HTTP 可以让您的应用运行更快、更节省流量。而OkHttp库就是为此而生。

OkHttp是一个高效的HTTP库:

  • 支持 SPDY ,共享同一个Socket来处理同一个服务器的所有请求

  • 如果SPDY不可用,则通过连接池来减少请求延时

  • 无缝的支持GZIP来减少数据流量

  • 缓存响应数据来减少重复的网络请求

会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。

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

OKHttp源码位置https://github.com/square/okhttp

使用

简单使用代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private final OkHttpClient client =  new  OkHttpClient();
public void run() throws Exception {
     Request request =  new  Request.Builder()
         .header( "User-Agent" "OkHttp Headers.java" )
         .addHeader( "Accept" "application/json; q=0.5" )
         .addHeader( "Accept" "application/vnd.github.v3+json" )
         .build();
     Response response = client.newCall(request).execute();
     if  (!response.isSuccessful())  throw  new  IOException( "Unexpected code "  + response);
     System.out.println( "Server: "  + response.header( "Server" ));
     System.out.println( "Date: "  + response.header( "Date" ));
     System.out.println( "Vary: "  + response.headers( "Vary" ));
}

在这里使用不做详细介绍,推荐一篇关于OKHttp的详细使用教程,下面转入源码的分析。

总体设计


上 面是OKHttp总体设计图,主要是通过Diapatcher不断从RequestQueue中取出请求(Call),根据是否已缓存调用Cache或 Network这两类数据获取接口之一,从内存缓存或是服务器取得请求的数据。该引擎有同步和异步请求,同步请求通过Call.execute()直接返 回当前的Response,而异步请求会把当前的请求Call.enqueue添加(AsyncCall)到请求队列中,并通过回调(Callback) 的方式来获取最后结果。

接下来会介绍一些比较重要的类,另外一些基础IO方面的内容主要来之iohttp这个包。这些类的解释大部分来至文档介绍本身,所以在此不会翻译成中文,本人觉得英语原文更能准确表达它自身的作用。

OKHttp中重要的类

1.Route.java
The concrete route used by a connection to reach an abstract origin server.
When creating a connection the client has many options:

  • HTTP proxy: a proxy server may be explicitly configured for the client. Otherwise the {@linkplain java.net.ProxySelector proxy selector} is used. It may return multiple proxies to attempt.

  • IP address: whether connecting directly to an origin server or a proxy, opening a socket requires an IP address. The DNS server may return multiple IP addresses to attempt.

  • TLS configuration: which cipher suites and TLS versions to attempt with the HTTPS connection.

Each route is a specific selection of these options.
其实就是对地址的一个封装类,但是很重要。

2.Platform.java
Access to platform-specific features.

  • Server name indication (SNI): Supported on Android 2.3+.

  • Session Tickets: Supported on Android 2.3+.

  • Android Traffic Stats (Socket Tagging): Supported on Android 4.0+.

  • ALPN (Application Layer Protocol Negotiation): Supported on Android 5.0+. The APIs were present in Android 4.4, but that implementation was unstable.

Supported on OpenJDK 7 and 8 (via the JettyALPN-boot library).
这个类主要是做平台适应性,针对Android2.3到5.0后的网络请求的适配支持。同时,在这个类中能看到针对不同平台,通过java反射不同的class是不一样的。

3.Connnection.java
The sockets and streams of an HTTP, HTTPS, or HTTPS+SPDY connection. May be used for multiple HTTP request/response exchanges. Connections may be direct to the origin server or via a proxy.
Typically instances of this class are created, connected and exercised automatically by the HTTP client. Applications may use this class to monitor HTTP connections as members of a ConnectionPool.
Do not confuse this class with the misnamed HttpURLConnection, which isn’t so much a connection as a single request/response exchange.
Modern TLS
There are tradeoffs when selecting which options to include when negotiating a secure connection to a remote host. Newer TLS options are quite useful:

  • Server Name Indication (SNI) enables one IP address to negotiate secure connections for multiple domain names.

  • Application Layer Protocol Negotiation (ALPN) enables the HTTPS port (443) to be used for different HTTP and SPDY protocols.

Unfortunately, older HTTPS servers refuse to connect when such options are presented. Rather than avoiding these options entirely, this class allows a connection to be attempted with modern options and then retried without them should the attempt fail.

4.ConnnectionPool.java
Manages reuse of HTTP and SPDY connections for reduced network latency. HTTP requests that share the same Address may share a Connection. This class implements the policy of which connections to keep open for future use.
The  system-wide default uses system properties for tuning parameters:

  • http.keepAlive true if HTTP and SPDY connections should be pooled at all. Default is true.

  • http.maxConnections maximum number of idle connections to each to keep in the pool. Default is 5.

  • http.keepAliveDuration Time in milliseconds to keep the connection alive in the pool before closing it. Default is 5 minutes. This property isn’t used by HttpURLConnection.

The default instance doesn’t adjust its configuration as system properties are changed. This assumes that the applications that set these parameters do so before making HTTP connections, and that this class is initialized lazily.

5.Request.java
An HTTP request. Instances of this class are immutable if their body is null or itself immutable.(Builder模式)

6.Response.java
An HTTP response. Instances of this class are not immutable: the response body is a one-shot value that may be consumed only once. All other properties are immutable.

7.Call.java
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.

8.Dispatcher.java
Policy on when async requests are executed.

Each dispatcher uses an ExecutorService to run calls internally. If you supply your own executor, it should be able to run configured maximum number of calls concurrently.

9.HttpEngine.java
Handles a single HTTP request/response pair. Each HTTP engine follows this
lifecycle:

  • It is created.

  • The HTTP request message is sent with sendRequest(). Once the request is sent it is an error to modify the request headers. After sendRequest() has been called the request body can be written to if it exists.

  • The HTTP response message is read with readResponse(). After the response has been read the response headers and body can be read. All responses have a response body input stream, though in some instances this stream is empty.

The request and response may be served by the HTTP response cache, by the network, or by both in the event of a conditional GET.

10.Internal.java
Escalate internal APIs in {@code com.squareup.okhttp} so they can be used from OkHttp’s implementation packages. The only implementation of this interface is in {@link com.squareup.okhttp.OkHttpClient}.

11.Cache.java
Caches HTTP and HTTPS responses to the filesystem so they may be reused, saving time and bandwidth.

Cache Optimization
To measure cache effectiveness, this class tracks three statistics:

  • Request Count: the number of HTTP requests issued since this cache was created.

  • Network Count: the number of those requests that required network use.

  • Hit Count: the number of those requests whose responses were served by the cache.

Sometimes a request will result in a conditional cache hit. If the cache contains a stale copy of the response, the client will issue a conditional GET. The server will then send either the updated response if it has changed, or a short ‘not modified’ response if the client’s copy is still valid. Such responses increment both the network count and hit count.
The best way to improve the cache hit rate is by configuring the web server to return cacheable responses. Although this client honors all HTTP/1.1 (RFC 2068) cache headers, it doesn’t cache partial responses.

Force a Network Response
In some situations, such as after a user clicks a ‘refresh’ button, it may be necessary to skip the cache, and fetch data directly from the server. To force a full refresh, add the {@code no-cache} directive:

<div id="highlighter_68230" class="syntaxhighlighter js" style="box-sizing: border-box; border: 0px; padding: 0px; margin: 1em 0px !important; width: 100% !important; position: re
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值