使用 Get a URL 1 2 3 OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(url).build(); Response response = client.newCall(request).execute()
可以看到,完成一个Get请求需要OkHttpClient类型对象和Request类型对象。
建造者模式 简介 这种类型的设计模式属于创建型模式,它提供了一种创建对象的方式。
建造者模式关注该对象是如何一步一步创建而成的,对于用户而言,无须知道创建过程和内部组成细节。
OkHttpClient的创建 由构造器直接创建 1 public final OkHttpClient client = new OkHttpClient();
由Builder创建 1 2 3 4 public final OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new HttpLoggingInterceptor()) .cache(new Cache(cacheDir, cacheSize)) .build();
一步步来看这个过程,首先new 了一个OkHttpClient.Builder(),即一个Builder类型的对象,这个Builder是OkHttpClient的内部类。
Builder的构造器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public Builder () { dispatcher = new Dispatcher(); protocols = DEFAULT_PROTOCOLS; connectionSpecs = DEFAULT_CONNECTION_SPECS; eventListenerFactory = EventListener.factory(EventListener.NONE); proxySelector = ProxySelector.getDefault(); if (proxySelector == null ) { proxySelector = new NullProxySelector(); } cookieJar = CookieJar.NO_COOKIES; socketFactory = SocketFactory.getDefault(); hostnameVerifier = OkHostnameVerifier.INSTANCE; certificatePinner = CertificatePinner.DEFAULT; proxyAuthenticator = Authenticator.NONE; authenticator = Authenticator.NONE; connectionPool = new ConnectionPool(); dns = Dns.SYSTEM; followSslRedirects = true ; followRedirects = true ; retryOnConnectionFailure = true ; callTimeout = 0 ; connectTimeout = 10_000 ; readTimeout = 10_000 ; writeTimeout = 10_000 ; pingInterval = 0 ; }
其实就是对Builder中的参数进行初始化赋值操作。
Builder#addInterceptor() 1 2 3 4 5 public Builder addInterceptor (Interceptor interceptor) { if (interceptor == null ) throw new IllegalArgumentException("interceptor == null" ); interceptors.add(interceptor); return this ; }
addInterceptor方法为Builder中的List interceptors类型的interceptors添加值,返回的是原先的Builder类型对象
Builder#cache() 1 2 3 4 5 public Builder cache (@Nullable Cache cache) { this .cache = cache; this .internalCache = null ; return this ; }
cache方法同理,对Builder中的cache参数赋值。返回的依旧是原先的Builder类型对象。
这些方法其实和常见的set方法很像,但最大的区别是,通常的set方法不返回任何值,仅仅可以一次调用。而Builder类中的这些方法依旧返回在原先基础上修改过的Builder对象,所以我们可以在这个Builder对象上继续修改,实现我们所见的连续调用操作。
但至此,我们只是构建好了Builder类型对象,这与OkHttpClient的创建有什么联系呢?
在用Builder创建时,除了调用上述的两个返回值类型为Builder的方法,还调用了build方法。
Builder#build() 1 2 3 public OkHttpClient build () { return new OkHttpClient(this ); }
这个方法的返回值是OkHttpClient。它调用了OkHttpClient的构造方法,并将自身作为参数传入。
OkHttpClient(Builder builder) 用Builder的参数为OkHttpClient赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 OkHttpClient(Builder builder) { this .dispatcher = builder.dispatcher; this .proxy = builder.proxy; this .protocols = builder.protocols; this .connectionSpecs = builder.connectionSpecs; this .interceptors = Util.immutableList(builder.interceptors); this .networkInterceptors = Util.immutableList(builder.networkInterceptors); this .eventListenerFactory = builder.eventListenerFactory; this .proxySelector = builder.proxySelector; this .cookieJar = builder.cookieJar; this .cache = builder.cache; this .internalCache = builder.internalCache; this .socketFactory = builder.socketFactory; boolean isTLS = false ; for (ConnectionSpec spec : connectionSpecs) { isTLS = isTLS || spec.isTls(); } if (builder.sslSocketFactory != null || !isTLS) { this .sslSocketFactory = builder.sslSocketFactory; this .certificateChainCleaner = builder.certificateChainCleaner; } else { X509TrustManager trustManager = Util.platformTrustManager(); this .sslSocketFactory = newSslSocketFactory(trustManager); this .certificateChainCleaner = CertificateChainCleaner.get(trustManager); } if (sslSocketFactory != null ) { Platform.get().configureSslSocketFactory(sslSocketFactory); } this .hostnameVerifier = builder.hostnameVerifier; this .certificatePinner = builder.certificatePinner.withCertificateChainCleaner( certificateChainCleaner); this .proxyAuthenticator = builder.proxyAuthenticator; this .authenticator = builder.authenticator; this .connectionPool = builder.connectionPool; this .dns = builder.dns; this .followSslRedirects = builder.followSslRedirects; this .followRedirects = builder.followRedirects; this .retryOnConnectionFailure = builder.retryOnConnectionFailure; this .callTimeout = builder.callTimeout; this .connectTimeout = builder.connectTimeout; this .readTimeout = builder.readTimeout; this .writeTimeout = builder.writeTimeout; this .pingInterval = builder.pingInterval; if (interceptors.contains(null )) { throw new IllegalStateException("Null interceptor: " + interceptors); } if (networkInterceptors.contains(null )) { throw new IllegalStateException("Null network interceptor: " + networkInterceptors); } }
其实,OkHttpClient的无参构造方法也是调用了参数为Builder的构造方法,只是它传入的是默认创建的Builder
1 2 3 public OkHttpClient() { this(new Builder()); }
由newBuilder创建 你可以使用newBuilder()来定制一个共享 的OkHttpClient实例。这将构建共享相同连接池、线程池和配置的客户机。使用构建器方法为特定目的配置派生客户机。
1 2 OkHttpClient eagerClient = client.newBuilder(). readTimeout(500 , TimeUnit.MILLISECONDS).build();
client是已有的OkHttpClient实例,newBuilder是OkHttpClient类中的方法
OkHttpClient#newBuilder() 1 2 3 public Builder newBuilder () { return new Builder(this ); }
将自身作为参数传给Builder的构造方法
Builder(OkHttpClient okHttpClient) 用OkHttpClient对象的参数初始化Builder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 Builder(OkHttpClient okHttpClient) { this .dispatcher = okHttpClient.dispatcher; this .proxy = okHttpClient.proxy; this .protocols = okHttpClient.protocols; this .connectionSpecs = okHttpClient.connectionSpecs; this .interceptors.addAll(okHttpClient.interceptors); this .networkInterceptors.addAll(okHttpClient.networkInterceptors); this .eventListenerFactory = okHttpClient.eventListenerFactory; this .proxySelector = okHttpClient.proxySelector; this .cookieJar = okHttpClient.cookieJar; this .internalCache = okHttpClient.internalCache; this .cache = okHttpClient.cache; this .socketFactory = okHttpClient.socketFactory; this .sslSocketFactory = okHttpClient.sslSocketFactory; this .certificateChainCleaner = okHttpClient.certificateChainCleaner; this .hostnameVerifier = okHttpClient.hostnameVerifier; this .certificatePinner = okHttpClient.certificatePinner; this .proxyAuthenticator = okHttpClient.proxyAuthenticator; this .authenticator = okHttpClient.authenticator; this .connectionPool = okHttpClient.connectionPool; this .dns = okHttpClient.dns; this .followSslRedirects = okHttpClient.followSslRedirects; this .followRedirects = okHttpClient.followRedirects; this .retryOnConnectionFailure = okHttpClient.retryOnConnectionFailure; this .callTimeout = okHttpClient.callTimeout; this .connectTimeout = okHttpClient.connectTimeout; this .readTimeout = okHttpClient.readTimeout; this .writeTimeout = okHttpClient.writeTimeout; this .pingInterval = okHttpClient.pingInterval; }
建造者模式的优点
用于创建对象Builder其实是可以共享的,我们可以用同一个Builder类型的对象创建出不同的实例。
可以让用户不需要关心构造的具体细节,只需要指定想更改的参数。
OkHttp中的Request也用来建造者模式
责任链模式 简介 将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象。
责任链模式有两种情况,一种是要求具体的处理对象只能选择承担责任或把责任继续传递,不能承担责任后又继续将责任往下传。另一种是,一个责任可以被不同的对象接收,即不论当前对象是否处理该责任,都可以终止传递或继续传递。
引言 使用OkHttp进行Get请求的代码如下
1 Response response = client.newCall(request).execute()
client.newCall(request)将会返回一个Call类型的实例,实际为RealCall类的对象。它的execute()方法如下
RealCall#execute() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @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 ); } }
正常情况下,它的返回值是 getResponseWithInterceptorChain()。这个方法就涉及到了责任链模式
RealCall#getResponseWithInterceptorChain() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 Response getResponseWithInterceptorChain () throws IOException { 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 ); } } }
首先将所有拦截器放入一个list中,传给RealInterceptorChain构建对象。然后调用Response response = chain.proceed(originalRequest);即可得到response。
RealInterceptorChain#proceed() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @Override public Response proceed (Request request) throws IOException { return proceed(request, transmitter, exchange); } public Response proceed (Request request, Transmitter transmitter, @Nullable Exchange exchange) throws IOException { if (index >= interceptors.size()) throw new AssertionError(); calls++; if (this .exchange != null && !this .exchange.connection().supportsUrl(request.url())) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1 ) + " must retain the same host and port" ); } if (this .exchange != null && calls > 1 ) { throw new IllegalStateException("network interceptor " + interceptors.get(index - 1 ) + " must call proceed() exactly once" ); } RealInterceptorChain next = new RealInterceptorChain(interceptors, transmitter, exchange, index + 1 , request, call, connectTimeout, readTimeout, writeTimeout); Interceptor interceptor = interceptors.get(index); Response response = interceptor.intercept(next); if (exchange != null && index + 1 < interceptors.size() && next.calls != 1 ) { throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once" ); } if (response == null ) { throw new NullPointerException("interceptor " + interceptor + " returned null" ); } if (response.body() == null ) { throw new IllegalStateException( "interceptor " + interceptor + " returned a response with no body" ); } return response; }
这里的interceptors是构造RealInterceptorChain时传入的拦截器list
这个方法将会调用当前index的Interceptor实例,将
1 2 3 RealInterceptorChain next = newRealInterceptorChain(interceptors, transmitter, exchange, index + 1 , request, call, connectTimeout, readTimeout, writeTimeout);
作为参数传给Interceptor的intercept方法得到response。
接下来看一下不同的Interceptor的intercept方法
RetryAndFollowUpInterceptor#intercept() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Override public Response intercept (Chain chain) throws IOException { Request request = chain.request(); RealInterceptorChain realChain = (RealInterceptorChain) chain; Response response; boolean success = false ; try { response = realChain.proceed(request, transmitter, null ); success = true ; } catch (RouteException e) { } }
response = realChain.proceed(request, transmitter, null);
继续调用chain的proceed方法。也就是上面说的RealInterceptorChain的proceed方法。
BridgeInterceptor#intercept() 1 2 3 4 5 6 7 8 9 10 11 @Override public Response intercept (Chain chain) throws IOException { Request userRequest = chain.request(); Request.Builder requestBuilder = userRequest.newBuilder(); Response networkResponse = chain.proceed(requestBuilder.build()); return responseBuilder.build(); }
和上面的Interceptor一样,继续调用chain的proceed()
小结 其他的Interceptor也同理。无论它们其中的逻辑多复杂,都会涉及到对chain的proceed()方法调用 ,这样,request就一层一层地传递下去了。
且每个Interceptor的response都与chain的proceed()的返回值有关。这个返回值其实是下一个拦截器的response,下一个的response同理。这样就可以通过连续调用,在最开始的chain中得到调用过所有拦截器后的response了。
注意我这里说的是当前Interceptor的response与它后面的Interceptor的response有关,并不是等于的关系。因为当前的Interceptor往往还会根据获得的response进行进一步的操作,才得到最终要返回的response。
所以一个Interceptor的操作分为三个步骤,准备,发送,解析结果。
拦截器的作用
addInterceptor(Interceptor),这是由开发者设置的,会按照开发者的要求,在所有的拦截器处理之前进行最早的拦截处理,比如一些公共参数,Header都可以在这里添加。
RetryAndFollowUpInterceptor——失败和重定向拦截器
BridgeInterceptor——封装request和response拦截器
CacheInterceptor——缓存相关的过滤器,负责读取缓存直接返回、更新缓存
ConnectInterceptor——连接服务,负责和服务器建立连接
CallServerInterceptor——执行流操作(写出请求体、获得响应数据) 负责向服务器发送请求数据、从服务器读取响应数据 进行http请求报文的封装与请求报文的解析f
详解各个拦截器 这里只关注拦截器的intercept方法
RetryAndFollowUpInterceptor intercept 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 Override public Response intercept (Chain chain) throws IOException { Request request = chain.request(); RealInterceptorChain realChain = (RealInterceptorChain) chain; Transmitter transmitter = realChain.transmitter(); int followUpCount = 0 ; Response priorResponse = null ; while (true ) { transmitter.prepareToConnect(request); if (transmitter.isCanceled()) { throw new IOException("Canceled" ); } Response response; boolean success = false ; try { response = realChain.proceed(request, transmitter, null ); success = true ; } catch (RouteException e) { if (!recover(e.getLastConnectException(), transmitter, false , request)) { throw e.getFirstConnectException(); } continue ; } catch (IOException e) { boolean requestSendStarted = !(e instanceof ConnectionShutdownException); if (!recover(e, transmitter, requestSendStarted, request)) throw e; continue ; } finally { if (!success) { transmitter.exchangeDoneDueToException(); } } if (priorResponse != null ) { response = response.newBuilder() .priorResponse(priorResponse.newBuilder() .body(null ) .build()) .build(); } Exchange exchange = Internal.instance.exchange(response); Route route = exchange != null ? exchange.connection().route() : null ; Request followUp = followUpRequest(response, route); if (followUp == null ) { if (exchange != null && exchange.isDuplex()) { transmitter.timeoutEarlyExit(); } return response; } RequestBody followUpBody = followUp.body(); if (followUpBody != null && followUpBody.isOneShot()) { return response; } closeQuietly(response.body()); if (transmitter.hasExchange()) { exchange.detachWithViolence(); } if (++followUpCount > MAX_FOLLOW_UPS) { throw new ProtocolException("Too many follow-up requests: " + followUpCount); } request = followUp; priorResponse = response; } }
BridgeInterceptor intercept 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 @Override public Response intercept (Chain chain) throws IOException { Request userRequest = chain.request(); Request.Builder requestBuilder = userRequest.newBuilder(); RequestBody body = userRequest.body(); if (body != null ) { MediaType contentType = body.contentType(); if (contentType != null ) { requestBuilder.header("Content-Type" , contentType.toString()); } long contentLength = body.contentLength(); if (contentLength != -1 ) { requestBuilder.header("Content-Length" , Long.toString(contentLength)); requestBuilder.removeHeader("Transfer-Encoding" ); } else { requestBuilder.header("Transfer-Encoding" , "chunked" ); requestBuilder.removeHeader("Content-Length" ); } } if (userRequest.header("Host" ) == null ) { requestBuilder.header("Host" , hostHeader(userRequest.url(), false )); } if (userRequest.header("Connection" ) == null ) { requestBuilder.header("Connection" , "Keep-Alive" ); } boolean transparentGzip = false ; if (userRequest.header("Accept-Encoding" ) == null && userRequest.header("Range" ) == null ) { transparentGzip = true ; requestBuilder.header("Accept-Encoding" , "gzip" ); } List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url()); if (!cookies.isEmpty()) { requestBuilder.header("Cookie" , cookieHeader(cookies)); } if (userRequest.header("User-Agent" ) == null ) { requestBuilder.header("User-Agent" , Version.userAgent()); } Response networkResponse = chain.proceed(requestBuilder.build()); HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers()); Response.Builder responseBuilder = networkResponse.newBuilder() .request(userRequest); if (transparentGzip && "gzip" .equalsIgnoreCase(networkResponse.header("Content-Encoding" )) && HttpHeaders.hasBody(networkResponse)) { GzipSource responseBody = new GzipSource(networkResponse.body().source()); Headers strippedHeaders = networkResponse.headers().newBuilder() .removeAll("Content-Encoding" ) .removeAll("Content-Length" ) .build(); responseBuilder.headers(strippedHeaders); String contentType = networkResponse.header("Content-Type" ); responseBuilder.body(new RealResponseBody(contentType, -1L , Okio.buffer(responseBody))); } return responseBuilder.build(); }
CacheInterceptor intercept 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 @Override public Response intercept (Chain chain) throws IOException { Response cacheCandidate = cache != null ? cache.get(chain.request()) : null ; long now = System.currentTimeMillis(); CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get(); Request networkRequest = strategy.networkRequest; Response cacheResponse = strategy.cacheResponse; if (cache != null ) { cache.trackResponse(strategy); } if (cacheCandidate != null && cacheResponse == null ) { closeQuietly(cacheCandidate.body()); } if (networkRequest == null && cacheResponse == null ) { return new Response.Builder() .request(chain.request()) .protocol(Protocol.HTTP_1_1) .code(504 ) .message("Unsatisfiable Request (only-if-cached)" ) .body(Util.EMPTY_RESPONSE) .sentRequestAtMillis(-1L ) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); } if (networkRequest == null ) { return cacheResponse.newBuilder() .cacheResponse(stripBody(cacheResponse)) .build(); } Response networkResponse = null ; try { networkResponse = chain.proceed(networkRequest); } finally { if (networkResponse == null && cacheCandidate != null ) { closeQuietly(cacheCandidate.body()); } } if (cacheResponse != null ) { if (networkResponse.code() == HTTP_NOT_MODIFIED) { Response response = cacheResponse.newBuilder() .headers(combine(cacheResponse.headers(), networkResponse.headers())) .sentRequestAtMillis(networkResponse.sentRequestAtMillis()) .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis()) .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build(); networkResponse.body().close(); cache.trackConditionalCacheHit(); cache.update(cacheResponse, response); return response; } else { closeQuietly(cacheResponse.body()); } } Response response = networkResponse.newBuilder() .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build(); if (cache != null ) { if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) { CacheRequest cacheRequest = cache.put(response); return cacheWritingResponse(cacheRequest, response); } if (HttpMethod.invalidatesCache(networkRequest.method())) { try { cache.remove(networkRequest); } catch (IOException ignored) { } } } return response; }
这个intercept方法涉及很多知识点,我们逐步分析了解
强制缓存和协商缓存 强制缓存 就是服务器会告诉客户端该怎么缓存,例如cache-Control 字段,随便举几个例子:
private:所有内容只有客户端可以缓存,Cache-Control的默认取值
max-age=xxx:表示缓存内容将在xxx秒后失效
no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
协商缓存 就是需要客户端和服务器进行协商后再决定是否使用缓存,比如强制缓存过期失效了,就要再次请求服务器,并带上缓存标志,例如Etag。 客户端再次 进行请求的时候,请求头带上If-None-Match,也就是之前服务器返回的Etag值。
Etag值就是文件的唯一标示,服务器通过某个算法对资源进行计算,取得一串值(类似于文件的md5值),之后将该值通过etag返回给客户端
然后服务器就会将Etag值和服务器本身文件的Etag值进行比较,如果一样则数据没改变,就返回304,代表你要请求的数据没改变,你直接用就行啦。 如果不一致,就返回新的数据,这时候的响应码就是正常的200。
注释1 1 Response cacheCandidate = cache != null ? cache.get(chain.request()) : null ;
这里的cache来自client.internalCache(),是构造CacheInterceptor的参数。
注释2 1 CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
new CacheStrategy.Factory(now, chain.request(), cacheCandidate)生成了CacheStrategy.Factory对象。
CacheStrategy.Factory()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public Factory (long nowMillis, Request request, Response cacheResponse) { this .nowMillis = nowMillis; this .request = request; this .cacheResponse = cacheResponse; if (cacheResponse != null ) { this .sentRequestMillis = cacheResponse.sentRequestAtMillis(); this .receivedResponseMillis = cacheResponse.receivedResponseAtMillis(); Headers headers = cacheResponse.headers(); for (int i = 0 , size = headers.size(); i < size; i++) { String fieldName = headers.name(i); String value = headers.value(i); if ("Date" .equalsIgnoreCase(fieldName)) { servedDate = HttpDate.parse(value); servedDateString = value; } else if ("Expires" .equalsIgnoreCase(fieldName)) { expires = HttpDate.parse(value); } else if ("Last-Modified" .equalsIgnoreCase(fieldName)) { lastModified = HttpDate.parse(value); lastModifiedString = value; } else if ("ETag" .equalsIgnoreCase(fieldName)) { etag = value; } else if ("Age" .equalsIgnoreCase(fieldName)) { ageSeconds = HttpHeaders.parseSeconds(value, -1 ); } } } }
CacheStrategy.Factory#get()
1 2 3 4 5 6 7 8 9 10 public CacheStrategy get () { CacheStrategy candidate = getCandidate(); if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) { return new CacheStrategy(null , null ); } return candidate; }
CacheStrategy.Factory#getCandidate()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 private CacheStrategy getCandidate () { if (cacheResponse == null ) { return new CacheStrategy(request, null ); } if (request.isHttps() && cacheResponse.handshake() == null ) { return new CacheStrategy(request, null ); } if (!isCacheable(cacheResponse, request)) { return new CacheStrategy(request, null ); } CacheControl requestCaching = request.cacheControl(); if (requestCaching.noCache() || hasConditions(request)) { return new CacheStrategy(request, null ); } CacheControl responseCaching = cacheResponse.cacheControl(); long ageMillis = cacheResponseAge(); long freshMillis = computeFreshnessLifetime(); if (requestCaching.maxAgeSeconds() != -1 ) { freshMillis = Math.min(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds())); } long minFreshMillis = 0 ; if (requestCaching.minFreshSeconds() != -1 ) { minFreshMillis = SECONDS.toMillis(requestCaching.minFreshSeconds()); } long maxStaleMillis = 0 ; if (!responseCaching.mustRevalidate() && requestCaching.maxStaleSeconds() != -1 ) { maxStaleMillis = SECONDS.toMillis(requestCaching.maxStaleSeconds()); } if (!responseCaching.noCache() && ageMillis + minFreshMillis < freshMillis + maxStaleMillis) { Response.Builder builder = cacheResponse.newBuilder(); if (ageMillis + minFreshMillis >= freshMillis) { builder.addHeader("Warning" , "110 HttpURLConnection \"Response is stale\"" ); } long oneDayMillis = 24 * 60 * 60 * 1000L ; if (ageMillis > oneDayMillis && isFreshnessLifetimeHeuristic()) { builder.addHeader("Warning" , "113 HttpURLConnection \"Heuristic expiration\"" ); } return new CacheStrategy(null , builder.build()); } String conditionName; String conditionValue; if (etag != null ) { conditionName = "If-None-Match" ; conditionValue = etag; } else if (lastModified != null ) { conditionName = "If-Modified-Since" ; conditionValue = lastModifiedString; } else if (servedDate != null ) { conditionName = "If-Modified-Since" ; conditionValue = servedDateString; } else { return new CacheStrategy(request, null ); } Headers.Builder conditionalRequestHeaders = request.headers().newBuilder(); Internal.instance.addLenient(conditionalRequestHeaders, conditionName, conditionValue); Request conditionalRequest = request.newBuilder() .headers(conditionalRequestHeaders.build()) .build(); return new CacheStrategy(conditionalRequest, cacheResponse); }
ConnectInterceptor 封装了socket连接和TLS握手等逻辑
intercept() 1 2 3 4 5 6 7 8 9 10 11 @Override public Response intercept (Chain chain) throws IOException { RealInterceptorChain realChain = (RealInterceptorChain) chain; Request request = realChain.request(); Transmitter transmitter = realChain.transmitter(); boolean doExtensiveHealthChecks = !request.method().equals("GET" ); Exchange exchange = transmitter.newExchange(chain, doExtensiveHealthChecks); return realChain.proceed(request, transmitter, exchange); }
连接的具体实现在transmitter.newExchange(chain, doExtensiveHealthChecks);方法中。
CallServerInterceptor 在上一个拦截器中建立完连接后,就需要在这个拦截器中进行发数据与读数据的工作了。
intercept() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 @Override public Response intercept (Chain chain) throws IOException { RealInterceptorChain realChain = (RealInterceptorChain) chain; Exchange exchange = realChain.exchange(); Request request = realChain.request(); long sentRequestMillis = System.currentTimeMillis(); exchange.writeRequestHeaders(request); boolean responseHeadersStarted = false ; Response.Builder responseBuilder = null ; if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null ) { if ("100-continue" .equalsIgnoreCase(request.header("Expect" ))) { exchange.flushRequest(); responseHeadersStarted = true ; exchange.responseHeadersStart(); responseBuilder = exchange.readResponseHeaders(true ); } if (responseBuilder == null ) { if (request.body().isDuplex()) { exchange.flushRequest(); BufferedSink bufferedRequestBody = Okio.buffer( exchange.createRequestBody(request, true )); request.body().writeTo(bufferedRequestBody); } else { BufferedSink bufferedRequestBody = Okio.buffer( exchange.createRequestBody(request, false )); request.body().writeTo(bufferedRequestBody); bufferedRequestBody.close(); } } else { exchange.noRequestBody(); if (!exchange.connection().isMultiplexed()) { exchange.noNewExchangesOnConnection(); } } } else { exchange.noRequestBody(); } if (request.body() == null || !request.body().isDuplex()) { exchange.finishRequest(); } if (!responseHeadersStarted) { exchange.responseHeadersStart(); } if (responseBuilder == null ) { responseBuilder = exchange.readResponseHeaders(false ); } Response response = responseBuilder .request(request) .handshake(exchange.connection().handshake()) .sentRequestAtMillis(sentRequestMillis) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); int code = response.code(); if (code == 100 ) { response = exchange.readResponseHeaders(false ) .request(request) .handshake(exchange.connection().handshake()) .sentRequestAtMillis(sentRequestMillis) .receivedResponseAtMillis(System.currentTimeMillis()) .build(); code = response.code(); } exchange.responseHeadersEnd(response); if (forWebSocket && code == 101 ) { response = response.newBuilder() .body(Util.EMPTY_RESPONSE) .build(); } else { response = response.newBuilder() .body(exchange.openResponseBody(response)) .build(); } if ("close" .equalsIgnoreCase(response.request().header("Connection" )) || "close" .equalsIgnoreCase(response.header("Connection" ))) { exchange.noNewExchangesOnConnection(); } if ((code == 204 || code == 205 ) && response.body().contentLength() > 0 ) { throw new ProtocolException( "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength()); } return response; }
具体进行向服务器发送header和body以及接收服务器返回的数据的操作。
核心工作都由 HttpCodec 对象完成,而 HttpCodec 实际上利用的是 Okio,而 Okio 实际上还是用的 Socket