OkHttp源码解析2
来源:互联网 发布:黑魂2日系妹捏脸数据 编辑:程序博客网 时间:2024/05/29 14:45
接着上一篇解析,主要是HttpEngine,这个类中有三个重要方法,也是OkHttp的主要方法:发送请求—-sendRequest(),读取响应—–readResponse(),处理重定向——-followUpRequest()。
一、发送请求—-sendRequest()
/** * 找出响应源是什么,同时,如果有需要,会打开一个套接字到该响应源。准备请求头部,并准备开始写入请求正文,如果响应源存在。 */ public void sendRequest() throws RequestException, RouteException, IOException { if (cacheStrategy != null) return; // Already sent. if (transport != null) throw new IllegalStateException(); //根据userRequest初始化一个新的Request Request request = networkRequest(userRequest); //根据OkHttpClient得到缓存 InternalCache responseCache = Internal.instance.internalCache(client); //如果缓存响应可用,即responseCache不为null,则根据键"request"从Cache中取出response Response cacheCandidate = responseCache != null ? responseCache.get(request) : null; long now = System.currentTimeMillis(); cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get(); networkRequest = cacheStrategy.networkRequest; cacheResponse = cacheStrategy.cacheResponse; //缓存可用if (responseCache != null) { responseCache.trackResponse(cacheStrategy);} //缓存不可用,就关闭。if (cacheCandidate != null && cacheResponse == null) { closeQuietly(cacheCandidate.body()); }//networkRequest != null,说明网络可用,且cache不可用if (networkRequest != null) { //建立一个新连接,除非从重定向中继承一个connection if (connection == null) { connect(); } transport = Internal.instance.newTransport(connection, this);if (callerWritesRequestBody && permitsRequestBody() && requestBodyOut == null) { long contentLength = OkHeaders.contentLength(request); if (bufferRequestBody) { if (contentLength > Integer.MAX_VALUE) { throw new IllegalStateException("Use setFixedLengthStreamingMode() or " + "setChunkedStreamingMode() for requests larger than 2 GiB.");}if (contentLength != -1) { transport.writeRequestHeaders(networkRequest); requestBodyOut = new RetryableSink((int) contentLength);} else { requestBodyOut = new RetryableSink();}} else { transport.writeRequestHeaders(networkRequest); requestBodyOut = transport.createRequestBody(networkRequest, contentLength); } } } else {//networkRequest为null, 要么cache可用,要么网络被禁止使用 // We aren't using the network. Recycle a connection we may have inherited from a redirect. if (connection != null) { Internal.instance.recycle(client.getConnectionPool(), connection); connection = null; } if (cacheResponse != null) { //缓存响应可用,就通过cacheResponse给userResponse赋值 // We have a valid cached response. Promote it to the user response immediately. this.userResponse = cacheResponse.newBuilder() .request(userRequest) .priorResponse(stripBody(priorResponse)) .cacheResponse(stripBody(cacheResponse)) .build(); } else { //如果网络被禁止使用,且缓存不可用,就构造一个504的Response,并赋值给userResponse this.userResponse = new Response.Builder() .request(userRequest) .priorResponse(stripBody(priorResponse)) .protocol(Protocol.HTTP_1_1) .code(504) .message("Unsatisfiable Request (only-if-cached)") .body(EMPTY_BODY) .build(); } //根据缓存response 或者 自己构造的504 Response进行gzip压缩 userResponse = unzip(userResponse); } }
中间有用到缓存处理策略
public final class CacheStrategy {//返回一个策略以满足使用缓存响应的requestpublic CacheStrategy get() { CacheStrategy candidate = getCandidate(); if (candidate.networkRequest != null && request.cacheControl().onlyIfCached()) {//网络被禁止使用,且cache不可用,就创建新的CacheStrategy // We're forbidden from using the network and the cache is insufficient. return new CacheStrategy(null, null); } return candidate;}/** 返回一个策略以取得可以使用网络的request */private CacheStrategy getCandidate() { // 没有cacheResponse,也就是cache不可用 if (cacheResponse == null) {//最终就是走网络,所以把第二个参数置为null return new CacheStrategy(request, null); }//对于https,如果缺少必要的握手,则删除该缓存响应,认为cache不可用。 if (request.isHttps() && cacheResponse.handshake() == null) {//最终就是走网络,所以把第二个参数置为null return new CacheStrategy(request, null); } if (!isCacheable(cacheResponse, request)) {//最终就是走网络,所以把第二个参数置为null return new CacheStrategy(request, null); } CacheControl requestCaching = request.cacheControl(); if (requestCaching.noCache() || hasConditions(request)) {//最终就是走网络,所以把第二个参数置为null return new CacheStrategy(request, null); }//判断cache是否过期:通过是否过期,最后修改时间等 long ageMillis = cacheResponseAge(); long freshMillis = computeFreshnessLifetime(); if (requestCaching.maxAgeSeconds() != -1) { freshMillis = Math.min(freshMillis, SECONDS.toMillis(requestCaching.maxAgeSeconds())); } 省略........//如果cacheResponse可用,且不过期,就使用缓存,不走网络 return new CacheStrategy(null, builder.build()); } Request.Builder conditionalRequestBuilder = request.newBuilder(); 省略........}}
二、读取响应—–readResponse()
/*** 刷新剩余的请求头和正文,解析http响应头,并且开始读取http响应正文,前提是正文存在。*/public void readResponse() throws IOException { if (userResponse != null) { return; // Already ready. } //网络不可用,且缓存不可用 if (networkRequest == null && cacheResponse == null) { throw new IllegalStateException("call sendRequest() first!"); } //如果网络不可用,则说明没有可读取的响应体,就不再往下执行 if (networkRequest == null) { return; // No network response to read. } Response networkResponse; if (forWebSocket) { //将header写入socket transport.writeRequestHeaders(networkRequest); //发送request,并读取response networkResponse = readNetworkResponse(); } else if (!callerWritesRequestBody) { //先执行拦截器,再发送request,并读取response networkResponse = new com.squareup.okhttp.internal.http.HttpEngine.NetworkInterceptorChain(0, networkRequest).proceed(networkRequest); } else { //发送请求体buffer // Emit the request body's buffer so that everything is in requestBodyOut. if (bufferedRequestBody != null && bufferedRequestBody.buffer().size() > 0) { bufferedRequestBody.emit(); } // Emit the request headers if we haven't yet. We might have just learned the Content-Length. if (sentRequestMillis == -1) { if (OkHeaders.contentLength(networkRequest) == -1 && requestBodyOut instanceof RetryableSink) { long contentLength = ((RetryableSink) requestBodyOut).contentLength(); networkRequest = networkRequest.newBuilder() .header("Content-Length", Long.toString(contentLength)) .build(); } //写入到socket transport.writeRequestHeaders(networkRequest); } // 将请求体写入到socket if (requestBodyOut != null) { if (bufferedRequestBody != null) { // This also closes the wrapped requestBodyOut. bufferedRequestBody.close(); } else { requestBodyOut.close(); } if (requestBodyOut instanceof RetryableSink) { transport.writeRequestBody((RetryableSink) requestBodyOut); } } networkResponse = readNetworkResponse(); } receiveHeaders(networkResponse.headers()); // 如果缓存可用,且不过期,就使用缓存response if (cacheResponse != null) { if (validate(cacheResponse, networkResponse)) { userResponse = cacheResponse.newBuilder() .request(userRequest) .priorResponse(stripBody(priorResponse)) .headers(combine(cacheResponse.headers(), networkResponse.headers())) .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build(); networkResponse.body().close(); releaseConnection(); // Update the cache after combining headers but before stripping the // Content-Encoding header (as performed by initContentStream()). InternalCache responseCache = Internal.instance.internalCache(client); responseCache.trackConditionalCacheHit(); responseCache.update(cacheResponse, stripBody(userResponse)); userResponse = unzip(userResponse); return; } else { closeQuietly(cacheResponse.body()); } } //根据networkResponse构造response,并将其缓存 userResponse = networkResponse.newBuilder() .request(userRequest) .priorResponse(stripBody(priorResponse)) .cacheResponse(stripBody(cacheResponse)) .networkResponse(stripBody(networkResponse)) .build(); if (hasBody(userResponse)) { maybeCache(); userResponse = unzip(cacheWritingResponse(storeRequest, userResponse)); } }
还有中间方法
private Response readNetworkResponse() throws IOException { //将请求刷新出去 transport.finishRequest(); //读取response headers并构造networkResponse Response networkResponse = transport.readResponseHeaders() .request(networkRequest) .handshake(connection.getHandshake()) .header(OkHeaders.SENT_MILLIS, Long.toString(sentRequestMillis)) .header(OkHeaders.RECEIVED_MILLIS, Long.toString(System.currentTimeMillis())) .build(); if (!forWebSocket) { networkResponse = networkResponse.newBuilder() .body(transport.openResponseBody(networkResponse)) .build(); } Internal.instance.setProtocol(connection, networkResponse.protocol()); return networkResponse; }
三、followUpRequest()
这个就是用来处理重定向的
0 0
- OkHttp源码解析2
- okhttp源码解析(2)
- OKHttp(2)——源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OkHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- OKHttp源码解析
- JQuery 当当网订单页
- JAVA 10进制转16进制高位在前地位在后
- Tomcat7.0的安装及配置
- redis动态增加内存(不重启)
- 线程间操作无效: 从不是创建控件“”的线程访问它~~~的解决方法~【转】
- OkHttp源码解析2
- AS3.0游戏内嵌网页
- RMQ (Range Minimum/Maximum Query)算法(查询区间最值)
- FluentValidation具体使用案例
- android matrix 最全方法详解与进阶(完整篇)
- Java并发编程实战
- jquery 添加插入元素技巧<前面和后面>
- Charles让你更方便的在Mac下抓取移动端http/https数据包(http://zhiqiangbuxi.cn/?p=281)
- HDU2084数塔(数字三角形)