美文网首页
Okhttp 数据流

Okhttp 数据流

作者: gczxbb | 来源:发表于2021-01-29 22:45 被阅读0次

    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是读取。


    任重而道远

    相关文章

      网友评论

          本文标题:Okhttp 数据流

          本文链接:https://www.haomeiwen.com/subject/nzaonhtx.html