OKHttp源码解析(三)

来源:互联网 发布:cms监控软件怎么连手机 编辑:程序博客网 时间:2024/05/21 04:00
public void readResponse() throws IOException {        if(this.userResponse == null) {            if(this.networkRequest == null && this.cacheResponse == null) {                throw new IllegalStateException("call sendRequest() first!");            } else if(this.networkRequest != null) {                Response networkResponse;                if(this.forWebSocket) {                    this.transport.writeRequestHeaders(this.networkRequest);                    networkResponse = this.readNetworkResponse();                } else if(!this.callerWritesRequestBody) {                //利用拦截器方式去做答复处理                    networkResponse = (new HttpEngine.NetworkInterceptorChain(0, this.networkRequest)).proceed(this.networkRequest);                } else {                    //这个else分句可以不看                }                this.receiveHeaders(networkResponse.headers());                if(this.cacheResponse != null) {                    if(validate(this.cacheResponse, networkResponse)) {                        this.userResponse = this.cacheResponse.newBuilder().request(this.userRequest).priorResponse(stripBody(this.priorResponse)).headers(combine(this.cacheResponse.headers(), networkResponse.headers())).cacheResponse(stripBody(this.cacheResponse)).networkResponse(stripBody(networkResponse)).build();                        networkResponse.body().close();                        this.releaseConnection();                        InternalCache responseCache1 = Internal.instance.internalCache(this.client);                        responseCache1.trackConditionalCacheHit();                        responseCache1.update(this.cacheResponse, stripBody(this.userResponse));                        this.userResponse = this.unzip(this.userResponse);                        return;                    }                    Util.closeQuietly(this.cacheResponse.body());                }                this.userResponse = networkResponse.newBuilder().request(this.userRequest).priorResponse(stripBody(this.priorResponse)).cacheResponse(stripBody(this.cacheResponse)).networkResponse(stripBody(networkResponse)).build();                if(hasBody(this.userResponse)) {                    this.maybeCache();                    this.userResponse = this.unzip(this.cacheWritingResponse(this.storeRequest, this.userResponse));                }            }        }    }

在上篇文章结尾OKHttp源码解析(二) 我们分析到这里第10行的callerWritesRequestBody会为空,所以我会直接进去这个判断,同样在OKHttp源码解析(一) 我们分析过发送请求时使用的拦截器模式,这里对答复的操作也用了同样的方式,不同于请求调用的是intercept,这里用的是proceed,我们就来看看这个方法做了什么

public Response proceed(Request request) throws IOException {            ++this.calls;            if(this.index > 0) {                Interceptor response = (Interceptor)HttpEngine.this.client.networkInterceptors().get(this.index - 1);                Address code = this.connection().getRoute().getAddress();                if(!request.url().getHost().equals(code.getUriHost()) || Util.getEffectivePort(request.url()) != code.getUriPort()) {                    throw new IllegalStateException("network interceptor " + response + " must retain the same host and port");                }                if(this.calls > 1) {                    throw new IllegalStateException("network interceptor " + response + " must call proceed() exactly once");                }            }            if(this.index < HttpEngine.this.client.networkInterceptors().size()) {            //根据拦截器的数目去相应取出拦截器并执行intercept里面用户自定义的处理方式                HttpEngine.NetworkInterceptorChain var7 = HttpEngine.this.new NetworkInterceptorChain(this.index + 1, request);                Interceptor var10 = (Interceptor)HttpEngine.this.client.networkInterceptors().get(this.index);                Response interceptedResponse = var10.intercept(var7);                if(var7.calls != 1) {                    throw new IllegalStateException("network interceptor " + var10 + " must call proceed() exactly once");                } else {                    return interceptedResponse;                }            } else {            //写入请求头部                    HttpEngine.this.transport.writeRequestHeaders(request);                HttpEngine.this.networkRequest = request;                if(HttpEngine.this.permitsRequestBody() && request.body() != null) {                //写入一些请求体                    Sink var5 = HttpEngine.this.transport.createRequestBody(request, request.body().contentLength());                    BufferedSink var8 = Okio.buffer(var5);                    request.body().writeTo(var8);                    var8.close();                }                //将之前写入的数据flush给socket并读取服务器答复                Response var6 = HttpEngine.this.readNetworkResponse();                int var9 = var6.code();                if((var9 == 204 || var9 == 205) && var6.body().contentLength() > 0L) {                    throw new ProtocolException("HTTP " + var9 + " had non-zero Content-Length: " + var6.body().contentLength());                } else {                    return var6;                }            }        }

我们先来看看27行的头部写入是怎么一个写法

public void writeRequestHeaders(Request request) throws IOException {        this.httpEngine.writingRequestHeaders();        //组装请求的信息,比如url,请求方式,请求协议        String requestLine = RequestLine.get(request, this.httpEngine.getConnection().getRoute().getProxy().type(), this.httpEngine.getConnection().getProtocol());        //将请求头和请求体写入socket        this.httpConnection.writeRequest(request.headers(), requestLine);    }public void writeRequest(Headers headers, String requestLine) throws IOException {        if(this.state != 0) {            throw new IllegalStateException("state: " + this.state);        } else {            this.sink.writeUtf8(requestLine).writeUtf8("\r\n");            int i = 0;            for(int size = headers.size(); i < size; ++i) {                this.sink.writeUtf8(headers.name(i)).writeUtf8(": ").writeUtf8(headers.value(i)).writeUtf8("\r\n");            }            this.sink.writeUtf8("\r\n");            this.state = 1;        }    }

上面的sink就是socket的写入流,在上篇文章我们分析过怎么得到它的,将请求头部和请求体写入socket后,proceed的第37行就要进行flush操作了

private Response readNetworkResponse() throws IOException {    //执行flush操作        this.transport.finishRequest();        //等待服务器相应并读取服务器返回信息组装成我们需要的response        Response networkResponse = this.transport.readResponseHeaders().request(this.networkRequest).handshake(this.connection.getHandshake()).header(OkHeaders.SENT_MILLIS, Long.toString(this.sentRequestMillis)).header(OkHeaders.RECEIVED_MILLIS, Long.toString(System.currentTimeMillis())).build();        if(!this.forWebSocket) {        //组装response的body            networkResponse = networkResponse.newBuilder().body(this.transport.openResponseBody(networkResponse)).build();        }        Internal.instance.setProtocol(this.connection, networkResponse.protocol());        return networkResponse;    }

先简单看下第三行finishRequest调用的代码

public void finishRequest() throws IOException {        this.httpConnection.flush();    }public void flush() throws IOException {        this.sink.flush();    }

再来看看第5行的组装步骤

public Builder readResponseHeaders() throws IOException {        return this.httpConnection.readResponse();    }public Builder readResponse() throws IOException {        if(this.state != 1 && this.state != 3) {            throw new IllegalStateException("state: " + this.state);        } else {            try {                StatusLine e;                Builder exception1;                do {                //从输入流里读出答复并组装成答复消息                    e = StatusLine.parse(this.source.readUtf8LineStrict());                    exception1 = (new Builder()).protocol(e.protocol).code(e.code).message(e.message);                    com.squareup.okhttp.Headers.Builder headersBuilder = new com.squareup.okhttp.Headers.Builder();                    //答复头部的读取                    this.readHeaders(headersBuilder);                    headersBuilder.add(OkHeaders.SELECTED_PROTOCOL, e.protocol.toString());                    exception1.headers(headersBuilder.build());                } while(e.code == 100);                this.state = 4;                return exception1;            } catch (EOFException var4) {                IOException exception = new IOException("unexpected end of stream on " + this.connection + " (recycle count=" + Internal.instance.recycleCount(this.connection) + ")");                exception.initCause(var4);                throw exception;            }        }    }

上面的代码我们看到的是对答复头部的读取整理,而readNetworkResponse()第8行则是对服务器答复的body进行整理组装

public ResponseBody openResponseBody(Response response) throws IOException {        Source source = this.getTransferStream(response);        //最终返回一个输入流        return new RealResponseBody(response.headers(), Okio.buffer(source));    }    private Source getTransferStream(Response response) throws IOException {        if(!HttpEngine.hasBody(response)) {            return this.httpConnection.newFixedLengthSource(0L);        } else if("chunked".equalsIgnoreCase(response.header("Transfer-Encoding"))) {            return this.httpConnection.newChunkedSource(this.httpEngine);        } else {            long contentLength = OkHeaders.contentLength(response);            return contentLength != -1L?this.httpConnection.newFixedLengthSource(contentLength):this.httpConnection.newUnknownLengthSource();        }    }

在经过这么层层代码的深入(好多代码,看得都乱了吧),我们最终得到了服务器返回的userResponse。。

最后的最后,我们要回到OKHttp源码解析(一) 最后一段代码getResponse的52行得到我们上面分析的userResponse,并关闭相应的连接池,关闭回收socket等”善后“处理。

三篇文章分析到现在,算是把整个OKHttp的流程分析了个大概,OkHttp还有其他的一些部分,比如handshake,连接池的管理等方面的内容,如果有人有发现这方面介绍的好文章可以留言推荐给我看看,大家共同学习,共同进步。

10 0
原创粉丝点击