Okhttp 数据流

2021-01-29  本文已影响0人  gczxbb

Okio根据Socket,获取读写缓冲区,负责读写底层Request与Response的Header与Body消息,由Okio的BufferedSource与BufferedSink实现。

CallServerInterceptor拦截器

public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    //上一个拦截器ConnectInterceptor创建的HttpCpdec
    HttpCodec httpCodec = realChain.httpStream();
    StreamAllocation streamAllocation = realChain.streamAllocation();
    RealConnection connection = (RealConnection) realChain.connection();
    Request request = realChain.request();

    long sentRequestMillis = System.currentTimeMillis();

    realChain.eventListener().requestHeadersStart(realChain.call());
    httpCodec.writeRequestHeaders(request);
    realChain.eventListener().requestHeadersEnd(realChain.call(), request);

    Response.Builder responseBuilder = null;
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
        //请求Header{"Expect":"100-continue”}协议
        if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
            httpCodec.flushRequest();
            realChain.eventListener().responseHeadersStart(realChain.call());
            responseBuilder = httpCodec.readResponseHeaders(true);
        }
        if (responseBuilder == null) {
            realChain.eventListener().requestBodyStart(realChain.call());
            long contentLength = request.body().contentLength();
            CountingSink requestBodyOut =
                    new CountingSink(httpCodec.createRequestBody(request, contentLength));
            BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);

            request.body().writeTo(bufferedRequestBody);
            bufferedRequestBody.close();
            realChain.eventListener()
                    .requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
        } else if (!connection.isMultiplexed()) {
            streamAllocation.noNewStreams();
        }
    }
    //Sink的flush
    httpCodec.finishRequest();
    //利用Source读取Response的Header
    if (responseBuilder == null) {
        realChain.eventListener().responseHeadersStart(realChain.call());
        responseBuilder = httpCodec.readResponseHeaders(false);
    }
    Response response = responseBuilder
            .request(request)
            .handshake(streamAllocation.connection().handshake())
            .sentRequestAtMillis(sentRequestMillis)
            .receivedResponseAtMillis(System.currentTimeMillis())
            .build();
    int code = response.code();
    //服务端返回100,客户端即使没有发送100-continue,重新构建Response
    if (code == 100) {
        responseBuilder = httpCodec.readResponseHeaders(false);
        response = responseBuilder
                .request(request)
                .handshake(streamAllocation.connection().handshake())
                .sentRequestAtMillis(sentRequestMillis)
                .receivedResponseAtMillis(System.currentTimeMillis())
                .build();
        code = response.code();
    }
    realChain.eventListener()
            .responseHeadersEnd(realChain.call(), response);
    if (forWebSocket && code == 101) {
        response = response.newBuilder()
                .body(Util.EMPTY_RESPONSE)
                .build();
    } else {
        response = response.newBuilder()
                .body(httpCodec.openResponseBody(response))
                .build();
    }
    if ("close".equalsIgnoreCase(response.request().header("Connection"))
            || "close".equalsIgnoreCase(response.header("Connection"))) {
        streamAllocation.noNewStreams();
    }
    if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
        throw new ProtocolException(
                "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
    }
    return response;
}

Http1Codec类BufferedSink的writeUtf8方法写入请求headers。
1,请求body不空,且非GET和HEAD时,如果Header中包括(Expect:100-continue)协议,先flush请求一次,读取服务器返回信息。
2,服务器返回code 100时,先不创建Responsebuilder,返回null,继续将请求body写入。只有服务端支持100,或客户端不发送100-cotinue时,直接写入request.body()。
客户端发送了100-continue,但服务器不支持,将返回非100code,Responsebuilder不空,不会写入body。
3,flush刷新请求,读取服务器返回headers,根据builder构建Response,
4,客户端Header没有请求100-continue字段时,服务器发送一个code100,需要重新读取真实read the actual response,我怀疑是为了重试读取。

Request的header写入
写入header的第一行
GET url HTTP/1.1
下面一行开始是header内容的key和value

读取构建Response
协议。message,code,和header
一行一行的读取header
String line = source.readUtf8LineStrict(headerLimit);
构建Response的headers

第一行StatusLine statusLine = StatusLine.parse(readHeaderLine());
包括message,协议和code。
HTTP/1.1 403 Forbidden

总结

利用Okio框架操作IO,HttpCodec封装了BufferedSource和BufferedSink,数据流缓冲区读写,数据源是RealConnection的Socket。**BufferedSink是写入,BufferedSource是读取。


任重而道远

上一篇下一篇

猜你喜欢

热点阅读