OKHttp3源码解析(四)OKHttp的拦截器

继OKHttp3源码解析(一)同步请求的源码分析

继OKHttp3源码解析(二)同步请求的源码分析

继OKHttp3源码解析(三)OKHttp的任务调度Dispatcher

什么是拦截器

拦截器是OKHttp中提供一种强大机制,它可以实现网络监听,请求以及响应重写,请求失败重试等功能

当你发送一个请求的时候,OKHttp它会通过拦截器的链来执行Http请求,首先介绍OKHttp常用的拦截器

RetryAndFollowUpinterceptor    重试和失败重定向拦截器,主要做的是初始化的工作

BridgeInterceptor   桥接和适配拦截器   

CacheInterceptor 缓存拦截器   这两个主要功能是补充我们用户创建请求当中缺少的一些必须的http请求头和处理缓存的一些功能

ConnectIntercetor  连接拦截器 主要负责建立可用的连接

CallServerInterceptor 主要负责把http写进我们的IO流当中,并且我们会从网络IO流当中读取服务端返给我们客户端的数据

接下来看一下同步请求用到拦截器的源码:

看一下执行execute方法里获取response中getResponseWithInterceptorChain方法
Response result = this.getResponseWithInterceptorChain();

private Response getResponseWithInterceptorChain() throws IOException {
    List<Interceptor> interceptors = new ArrayList();//把所有的拦截器放到这个集合当中
    interceptors.addAll(this.client.interceptors());
    interceptors.add(this.retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(this.client.cookieJar()));
    interceptors.add(new CacheInterceptor(this.client.internalCache()));
    interceptors.add(new ConnectInterceptor(this.client));
    if (!this.retryAndFollowUpInterceptor.isForWebSocket()) {
        interceptors.addAll(this.client.networkInterceptors());
    }

    interceptors.add(new CallServerInterceptor(this.retryAndFollowUpInterceptor.isForWebSocket()));
    Chain chain = new RealInterceptorChain(interceptors, (StreamAllocation)null, (HttpStream)null, (Connection)null, 0, this.originalRequest);//然后将这个集合放到构造函数当中
    return chain.proceed(this.originalRequest);
}

上面方法首先做的是先把这几个拦截器都添加到一个集合当中,然后放到构造方法中接下来看一下proceed方法是如何实现的

public Response proceed(Request request) throws IOException {
    return this.proceed(request, this.streamAllocation, this.httpStream, this.connection);
}

public Response proceed(Request request, StreamAllocation streamAllocation, HttpStream httpStream, Connection connection) throws IOException {
    if (this.index >= this.interceptors.size()) {
        throw new AssertionError();
    } else {
        ++this.calls;
        if (this.httpStream != null && !this.sameConnection(request.url())) {
            throw new IllegalStateException("network interceptor " + this.interceptors.get(this.index - 1) + " must retain the same host and port");
        } else if (this.httpStream != null && this.calls > 1) {
            throw new IllegalStateException("network interceptor " + this.interceptors.get(this.index - 1) + " must call proceed() exactly once");
        } else {
			//当前创建的拦截器的链,但是参数是index +1,就说下面如果需要访问的话只能从下一个拦截器开始进行访问,而不能从当前拦截器,这样做就把整个拦截器构成了一个链条
            RealInterceptorChain next = new RealInterceptorChain(this.interceptors, streamAllocation, httpStream, connection, this.index + 1, request);
            Interceptor interceptor = (Interceptor)this.interceptors.get(this.index);
            Response response = interceptor.intercept(next);//执行索引index的intercept方法,然后将刚才所获的next拦截器的链传进去,这样就把所有的拦截器链构成了一个完整的链条
            if (httpStream != null && this.index + 1 < this.interceptors.size() && next.calls != 1) {
                throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once");
            } else if (response == null) {
                throw new NullPointerException("interceptor " + interceptor + " returned null");
            } else {
                return response;
            }
        }
    }
}

总结:第一步创建一系列拦截器,并将其中放入一个拦截器list集合中,第二步创建一个拦截器RealInterceptorChain,并执行拦截器链的proceed方法,proceed方法中创建下一个拦截器链,这样就会依次调用下一个拦截器的interceptor这个方法,这样就完整的构成了一个拦截器的链
首先看一下RetryAndFollowUpInterceptor拦截器中的intercept方法

public Response intercept(Chain chain) throws IOException {//主要的功能就是失败重连
        Request request = chain.request();
        this.streamAllocation = new StreamAllocation(this.client.connectionPool(), this.createAddress(request.url()));//用来获取连接服务端的connection和连接用于服务端的进行数据传输的输入输出流
        int followUpCount = 0;
        Response priorResponse = null;

        while(!this.canceled) {
            Response response = null;
            boolean releaseConnection = true;

            try {
                response = ((RealInterceptorChain)chain).proceed(request, this.streamAllocation, (HttpStream)null, (Connection)null);//执行了proceed方法说明会执行下一个拦截器的interceptor方法
                releaseConnection = false;
            } catch (RouteException var12) {
                if (!this.recover(var12.getLastConnectException(), true, request)) {
                    throw var12.getLastConnectException();
                }

                releaseConnection = false;
                continue;
            } catch (IOException var13) {
                if (!this.recover(var13, false, request)) {
                    throw var13;
                }

                releaseConnection = false;
                continue;
            } finally {
                if (releaseConnection) {
                    this.streamAllocation.streamFailed((IOException)null);
                    this.streamAllocation.release();
                }

            }

            if (priorResponse != null) {
                response = response.newBuilder().priorResponse(priorResponse.newBuilder().body((ResponseBody)null).build()).build();
            }

            Request followUp = this.followUpRequest(response);
            if (followUp == null) {
                if (!this.forWebSocket) {
                    this.streamAllocation.release();
                }

                return response;
            }

            Util.closeQuietly(response.body());
            ++followUpCount;
            if (followUpCount > 20) {
                this.streamAllocation.release();
                throw new ProtocolException("Too many follow-up requests: " + followUpCount);
            }

            if (followUp.body() instanceof UnrepeatableRequestBody) {
                throw new HttpRetryException("Cannot retry streamed HTTP body", response.code());
            }

            if (!this.sameConnection(response, followUp.url())) {
                this.streamAllocation.release();
                this.streamAllocation = new StreamAllocation(this.client.connectionPool(), this.createAddress(followUp.url()));
            } else if (this.streamAllocation.stream() != null) {
                throw new IllegalStateException("Closing the body of " + response + " didn't close its backing stream. Bad interceptor?");
            }

            request = followUp;
            priorResponse = response;
        }

        this.streamAllocation.release();
        throw new IOException("Canceled");
    }

有上面方法可知第一步在发起请求前对Request进行处理,第二步调用下一个拦截器获取response,第三步对response进行处理,返回给上一个拦截器

接下来具体看一下每一个拦截器

第一个拦截器RetryAndFollowUpinterceptor  (主要负责失败重连的)

进入源码查看,还是先看intercept 这个方法

public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    this.streamAllocation = new StreamAllocation(this.client.connectionPool(), this.createAddress(request.url()));
	//streamAllocation 就是用来建立执行Http请求所需要那些网络组件的,是用来分配Stream,它的作用获取连接服务端的Connection和用于服务端进行数据传输的输入输出流,主要传递给ConnectIntercetor所用的
    int followUpCount = 0;
    Response priorResponse = null;

    while(!this.canceled) {
		...
		try {
            response = ((RealInterceptorChain)chain).proceed(request, this.streamAllocation, (HttpStream)null, (Connection)null);//进行网络请求获取response
            releaseConnection = false;
        } catch (RouteException var12) {
		...
		}
        ++followUpCount;
        if (followUpCount > 20) { //这里有重试的次数进行判断(失败的网络重连,如果超出20次就不会进行请求了,这时候就会释放streamAllocation这个对象)
            this.streamAllocation.release();
            throw new ProtocolException("Too many follow-up requests: " + followUpCount);
    }

    ...
    }

    this.streamAllocation.release();
    throw new IOException("Canceled");
}

总结:第一步创建StreamAllocation对象用来建立Http请求所需要的所有的网络的组件,它的作用就是用来分配我们的Stream,第二步调用RealInterceptorChain.proceed(...)进行网络请求,第三步根据异常结果或者响应结果判断是否要进行重新请求,第四步,调用下一个拦截器,对response进行处理,返回给上一个拦截器。

第二个拦截器BridgeInterceptor   桥接和适配拦截器

主要负责内容 设置我们的内容长度以及我们的编码方式,设置我们的压缩,添加头部等作用

public Response intercept(Chain chain) throws IOException {
    Request userRequest = chain.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 != -1L) {
            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", Util.hostHeader(userRequest.url(), false));
    }

    if (userRequest.header("Connection") == null) {
        requestBuilder.header("Connection", "Keep-Alive");  //默认是Keep-Alive
    }

    boolean transparentGzip = false;
    if (userRequest.header("Accept-Encoding") == null) {
        transparentGzip = true;
        requestBuilder.header("Accept-Encoding", "gzip");
    }

    List<Cookie> cookies = this.cookieJar.loadForRequest(userRequest.url());
    if (!cookies.isEmpty()) {
        requestBuilder.header("Cookie", this.cookieHeader(cookies));
    }

    if (userRequest.header("User-Agent") == null) {
        requestBuilder.header("User-Agent", Version.userAgent());
    }

    Response networkResponse = chain.proceed(requestBuilder.build());//调用拦截器链的proceed方法,向服务器发送请求,服务器获取到请求之后回返回给客户端response
    HttpHeaders.receiveHeaders(this.cookieJar, userRequest.url(), networkResponse.headers());//所有的压缩解压的逻辑都是在这个方法里执行的,经过这个过程得到我们想要的response
    okhttp3.Response.Builder responseBuilder = networkResponse.newBuilder().request(userRequest);
    if (transparentGzip && "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding")) && HttpHeaders.hasBody(networkResponse)) {
		//将网络请求返回给我们的response进行转化,通过判断需要满足支持Gzip压缩的告诉我们的服务器这个客户端支持Gzip压缩的这样服务端才会返回给你支持Gzip压缩的Response
		//第二个判断gzip是否等于我们头部的Content-Encoding,一定要保证服务器的响应头是否支持Gzip压缩,第三步http请求头是否有body体
        GzipSource responseBody = new GzipSource(networkResponse.body().source());//将Gzip的body体转换成GzipSource这个类型,目的是为了调用者使用这个reponse body体的时候直接以解压的方式来读取这个流数据
        Headers strippedHeaders = networkResponse.headers().newBuilder().removeAll("Content-Encoding").removeAll("Content-Length").build();
        responseBuilder.headers(strippedHeaders);
        responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
    }

    return responseBuilder.build();
}

总结:第一步是负责将用户的一个Request请求转化为能够进行网络访问的请求,第二步将符合网络请求的Request进行网络请求,第三步将网络请求回来的响应Response转化为用户可用的Response

CacheInterceptor 缓存拦截器

OKHttp缓存策略 ,缓存策略的put方法

正常代码如下

OkHttpClient ok = new OkHttpClient
	.Builder()
	.cache(new Cache(new File("cache"),24*1024*1024)).build();
    Request request = new Request.Builder().url("http://www.baidu.com").build();
    Call call = ok.newCall(request);
    try {
        Response response = call.execute();
    } catch (IOException e) {
        e.printStackTrace();
    }

.cache方法里面创建了一个文件名为“cache”的文件缓存大小为24*1024*1024的文件

进入源码查看

private CacheRequest put(Response response) {
    String requestMethod = response.request().method();//获取requestMetohd
    if (HttpMethod.invalidatesCache(response.request().method())) {
        try {
            this.remove(response.request());
        } catch (IOException var6) {
            ;
        }

        return null;
    } else if (!requestMethod.equals("GET")) {//非get方法不缓存
        return null;
    } else if (HttpHeaders.hasVaryAll(response)) {
        return null;
    } else {
        Cache.Entry entry = new Cache.Entry(response);  //创建Entry实例
        DiskLruCache.Editor editor = null;//DiskLruCache来进行缓存的实际写入

        try {
            editor = this.cache.edit(urlToKey(response.request()));//用于写入缓存的
            if (editor == null) {
                return null;
            } else {
                entry.writeTo(editor);//真正的开始缓存,将我们的写入到磁盘上
                return new Cache.CacheRequestImpl(editor);//主要用于后面CacheInterceptor 缓存拦截器使用的
            }
        } catch (IOException var7) {
            this.abortQuietly(editor);
            return null;
        }
    }
}
public void writeTo(Editor editor) throws IOException {
        BufferedSink sink = Okio.buffer(editor.newSink(0));
        sink.writeUtf8(this.url).writeByte(10);//缓存url
        sink.writeUtf8(this.requestMethod).writeByte(10);//缓存请求方法
        sink.writeDecimalLong((long)this.varyHeaders.size()).writeByte(10);//缓存头部
        int i = 0;

        int size;
        for(size = this.varyHeaders.size(); i < size; ++i) {//遍历头部
            sink.writeUtf8(this.varyHeaders.name(i)).writeUtf8(": ").writeUtf8(this.varyHeaders.value(i)).writeByte(10);
        }

        sink.writeUtf8((new StatusLine(this.protocol, this.code, this.message)).toString()).writeByte(10);//缓存Http响应行
        sink.writeDecimalLong((long)(this.responseHeaders.size() + 2)).writeByte(10);//缓存响应的守护
        i = 0;

        for(size = this.responseHeaders.size(); i < size; ++i) {//遍历守护
            sink.writeUtf8(this.responseHeaders.name(i)).writeUtf8(": ").writeUtf8(this.responseHeaders.value(i)).writeByte(10);
        }

        sink.writeUtf8(SENT_MILLIS).writeUtf8(": ").writeDecimalLong(this.sentRequestMillis).writeByte(10);//缓存发送时间
        sink.writeUtf8(RECEIVED_MILLIS).writeUtf8(": ").writeDecimalLong(this.receivedResponseMillis).writeByte(10);//缓存接受响应的时间
        if (this.isHttps()) {//判断我们的请求是否是Https这个请求,之后才会进行握手以及证书信息的操作
            sink.writeByte(10);
            sink.writeUtf8(this.handshake.cipherSuite().javaName()).writeByte(10);
            this.writeCertList(sink, this.handshake.peerCertificates());
            this.writeCertList(sink, this.handshake.localCertificates());
            if (this.handshake.tlsVersion() != null) {
                sink.writeUtf8(this.handshake.tlsVersion().javaName()).writeByte(10);
            }
        }

        sink.close();
    }

缓存策略的get方法(用来从缓存读取我们的响应体response)

Response get(Request request) {
    String key = urlToKey(request);//通过url Md5解密获取key值

    DiskLruCache.Snapshot snapshot;//记录缓存某一个特定时刻所包含的内容
    try {
        snapshot = this.cache.get(key); //通过key值来获取缓存当中
        if (snapshot == null) {
            return null;
        }
    } catch (IOException var7) {
        return null;
    }

    Cache.Entry entry;//创建一个Entry
    try {
        entry = new Cache.Entry(snapshot.getSource(0));//如果通过这个key获取到这个缓存值
    } catch (IOException var6) {
        Util.closeQuietly(snapshot);
        return null;
    }

    Response response = entry.response(snapshot);//通过这个entry来获取这个Response
    if (!entry.matches(request, response)) {//如果一个请求和一个相应不是对应的话
        Util.closeQuietly(response.body());//关闭这个流
        return null;//返回空
    } else {
        return response;
    }
}

接下来进入主题

进入源码查看

public Response intercept(Chain chain) throws IOException {
    Response cacheCandidate = this.cache != null ? this.cache.get(chain.request()) : null; //如果当前缓存不为空的话去主动获取这个缓存否则执为空
    long now = System.currentTimeMillis();
    CacheStrategy strategy = (new Factory(now, chain.request(), cacheCandidate)).get();//缓存策略,可以使用网络也可以使用缓存进行对比来进行最好的策略
    Request networkRequest = strategy.networkRequest;//通过strategy对象获取到它内部的request
    Response cacheResponse = strategy.cacheResponse;//通过strategy对象获取到它内部的Response
    if (this.cache != null) {
        this.cache.trackResponse(strategy);//当有缓存的情况下更新一下相关的统计指标
    }

    if (cacheCandidate != null && cacheResponse == null) {
        Util.closeQuietly(cacheCandidate.body());//当前缓存不符合要求的话就需要关闭这个
    }

    if (networkRequest == null && cacheResponse == null) {//当前不能使用网络的同时又没有找到相应的缓存
	    //通过构建者模式构建一个response,会抛出一个504这个错误
        return (new Builder()).request(chain.request()).protocol(Protocol.HTTP_1_1).code(504).message("Unsatisfiable Request (only-if-cached)").body(EMPTY_BODY).sentRequestAtMillis(-1L).receivedResponseAtMillis(System.currentTimeMillis()).build();
    } else if (networkRequest == null) {//当前有缓存但是不能使用网络
	    //直接返回我们缓存的结果
        return cacheResponse.newBuilder().cacheResponse(stripBody(cacheResponse)).build();
    } else {
        Response networkResponse = null;

         try {
            networkResponse = chain.proceed(networkRequest);//通过调用拦截器的proceed方法来进行网络响应的获取,然后再交给下一个拦截器来做,下一个拦截器就是ConnectIntercetor  连接拦截器
            } finally {
            if (networkResponse == null && cacheCandidate != null) {
                Util.closeQuietly(cacheCandidate.body());
            }

        }

        Response response;
        if (cacheResponse != null) {
            if (validate(cacheResponse, networkResponse)) {//其实是判断当前network.code() 是否等于304,代表我们要从缓存中去获取
                response = cacheResponse.newBuilder().headers(combine(cacheResponse.headers(), networkResponse.headers())).cacheResponse(stripBody(cacheResponse)).networkResponse(stripBody(networkResponse)).build();
                networkResponse.body().close();
                this.cache.trackConditionalCacheHit();
                this.cache.update(cacheResponse, response);
                return response;
            }

            Util.closeQuietly(cacheResponse.body());
        }

        response = networkResponse.newBuilder().cacheResponse(stripBody(cacheResponse)).networkResponse(stripBody(networkResponse)).build();
        if (HttpHeaders.hasBody(response)) {//判断http头部有没有响应体
            CacheRequest cacheRequest = this.maybeCache(response, networkResponse.request(), this.cache);
            response = this.cacheWritingResponse(cacheRequest, response);//将我们的网络响应写入到我们的cache当中,下次取的时候就可以直接从缓存里获取了
        }

        return response;
    }
}
	
	

ConnectIntercetor  连接拦截器(打开与服务器正式的连接,正式开启OKHttp网络请求)

查看源码

public Response intercept(Chain chain) throws IOException {
    RealInterceptorChain realChain = (RealInterceptorChain)chain;
    Request request = realChain.request();
    StreamAllocation streamAllocation = realChain.streamAllocation();//用来建立执行Http请求所需要所有的那些网络的组件
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    HttpStream httpStream = streamAllocation.newStream(this.client, doExtensiveHealthChecks);//用来编码我们的request 以及解码我们的response
    RealConnection connection = streamAllocation.connection();//就是用来实际网络IO传输的
    return realChain.proceed(request, streamAllocation, httpStream, connection);//调用拦截器的操作
}

总结:第一步ConnectInterceptor通过拦截器链获取到前一个拦截器Interceptor传过来的StreamAllocation用来处理request,response,streamAllcation.newStream(),第二步将刚才创建的用于网络IO的Http1xStream对象,以及对于服务器交互最为关键的Http1xStream等对象传递给后面的拦截器。

public HttpStream newStream(OkHttpClient client, boolean doExtensiveHealthChecks) {
    int connectTimeout = client.connectTimeoutMillis();
    int readTimeout = client.readTimeoutMillis();
    int writeTimeout = client.writeTimeoutMillis();
    boolean connectionRetryEnabled = client.retryOnConnectionFailure();

    try {
	//获取RealConnection对象来进行实际的网络连接
        RealConnection resultConnection = this.findHealthyConnection(connectTimeout, readTimeout, writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
        Object resultStream;
        if (resultConnection.framedConnection != null) {//判断当前resultConnection是否可以复用,如果不可以复用就需要重新创建
            resultStream = new Http2xStream(client, this, resultConnection.framedConnection);
        } else {
            resultConnection.socket().setSoTimeout(readTimeout);
            resultConnection.source.timeout().timeout((long)readTimeout, TimeUnit.MILLISECONDS);
            resultConnection.sink.timeout().timeout((long)writeTimeout, TimeUnit.MILLISECONDS);
			//通过RealConnection 来获取resultStream对象
            resultStream = new Http1xStream(client, this, resultConnection.source, resultConnection.sink);
        }

        ConnectionPool var9 = this.connectionPool;
        synchronized(this.connectionPool) {
            this.stream = (HttpStream)resultStream;
            return (HttpStream)resultStream;
        }
    } catch (IOException var12) {
        throw new RouteException(var12);
    }
}

RealConnection中连接的源码如下

public void connect(int connectTimeout, int readTimeout, int writeTimeout, List<ConnectionSpec> connectionSpecs, boolean connectionRetryEnabled) {
	    //是否连接以及存在连接池当中
        if (this.protocol != null) {//判断当前是否已经连接了,如果已经连接了就会抛出异常
            throw new IllegalStateException("already connected");
        } else {
            RouteException routeException = null;
            ConnectionSpecSelector connectionSpecSelector = new ConnectionSpecSelector(connectionSpecs);//用于选择我们的连接
            if (this.route.address().sslSocketFactory() == null) {
                if (!connectionSpecs.contains(ConnectionSpec.CLEARTEXT)) {
                    throw new RouteException(new UnknownServiceException("CLEARTEXT communication not enabled for client"));
                }

                String host = this.route.address().url().host();
                if (!Platform.get().isCleartextTrafficPermitted(host)) {
                    throw new RouteException(new UnknownServiceException("CLEARTEXT communication to " + host + " not permitted by network security policy"));
                }
            }

            while(this.protocol == null) {
                try {
                    if (this.route.requiresTunnel()) {//是否需要建立tunnele这个隧道建立连接
                        this.buildTunneledConnection(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);
                    } else {
                        this.buildConnection(connectTimeout, readTimeout, writeTimeout, connectionSpecSelector);
                    }
                } catch (IOException var9) {
                    Util.closeQuietly(this.socket);
                    Util.closeQuietly(this.rawSocket);
                    this.socket = null;
                    this.rawSocket = null;
                    this.source = null;
                    this.sink = null;
                    this.handshake = null;
                    this.protocol = null;
                    if (routeException == null) {
                        routeException = new RouteException(var9);
                    } else {
                        routeException.addConnectException(var9);
                    }

                    if (!connectionRetryEnabled || !connectionSpecSelector.connectionFailed(var9)) {
                        throw routeException;
                    }
                }
            }

        }
    }

总结:第一步创建一个RealConnection对象目的是为了实际的网络请求,第二步是否需要隧道连接或者socket连接选择不同的连接方式,第三步最后会调用CallServerInterceptor这个拦截器来完成整个OKhttp的网络请求

线程池

其实内部连接池主要做了以下几点,第一点产生一个StreamAllocation对象第二点StreamAllocation对象的弱引用添加到RealConnecttion对象的allocations集合,第三点从连接池获取

okhttp使用了GC回收算法,StreamAllocation的数量会渐渐变成0,这样就会被线程池监听到并回收,这样就可以保持多个健康的keep-alive连接

CallServerInterceptor 拦截器 (主要负责向服务器发起真正的网络请求,并接受服务返回的响应)

源码分析

public Response intercept(Chain chain) throws IOException {
     HttpStream httpStream = ((RealInterceptorChain)chain).httpStream();//通过拦截器的链获取流对象
     StreamAllocation streamAllocation = ((RealInterceptorChain)chain).streamAllocation();//用来建立Http请求所需要的其他的网络组件,用来分配stream
     Request request = chain.request();//进行网络请求
     long sentRequestMillis = System.currentTimeMillis();
     httpStream.writeRequestHeaders(request);//向socket当中写入头部信息
    if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
         Sink requestBodyOut = httpStream.createRequestBody(request, request.body().contentLength());
         BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
         request.body().writeTo(bufferedRequestBody);//向socket当中写入我们的body信息
         bufferedRequestBody.close();
    }

    httpStream.finishRequest();//完成网络请求的写入工作
    Response response = httpStream.readResponseHeaders()//读取网络请求响应当中的头部信息
			.request(request)
			.handshake(streamAllocation.connection()
			.handshake()).sentRequestAtMillis(sentRequestMillis)
			.receivedResponseAtMillis(System.currentTimeMillis()).build();
    if (!this.forWebSocket || response.code() != 101) {
	    //创建一个response体
        response = response.newBuilder().body(httpStream.openResponseBody(response)).build(); 
    }

    if ("close".equalsIgnoreCase(response.request().header("Connection")) || "close".equalsIgnoreCase(response.header("Connection"))) {
	    //禁止新的流创建
        streamAllocation.noNewStreams();
    }

    int code = response.code();
    if ((code == 204 || code == 205) && response.body().contentLength() > 0L) {//如果获取code为204或者205抛出异常,否择传出response
        throw new ProtocolException("HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
    } else {
       return response;
    }
}

总结:第一步向socket当中写入头部信息 第二步向socket当中写入我们的body信息 第三步读取网络请求响应当中的头部信息第四步读取response

okHttp中一次网络请求的大致过程
第一步Call对象请求封装
第二步dispatcher对请求的分发
第三步getResponseWithInterceptors()方法 
通过拦截器链调用如下几个拦截器
1 RetryAndFollowUpinterceptor 重试和失败重定向拦截器  主要负责重试和重定向的请求   
2 CacheInterceptor 缓存拦截器   主要负责处理缓存的拦截器
3 BridgeInterceptor   桥接和适配拦截器   负责OKhttp请求和响应对象与实际Http响应和请求之间的转换
4 ConnectIntercetor  连接拦截器  负责建立连接
5 CallServerInterceptor 拦截器  负责完成最终的网络请求
 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
OkHttp是一个用于处理HTTP请求的开Java库。它提供了一个拦截机制,可以在发送请求和接收响应之前对它们进行修改和处理。以下是关于OkHttp拦截的一些介绍和示例: 1. OkHttp拦截是一个接口,它有一个方法intercept(Chain chain),该方法接收一个Chain对象作为参数,该对象表示当前的拦截链。 2. 拦截链是按照添加顺序执行的,每个拦截都可以选择将请求传递给下一个拦截或者直接返回响应。 3. 拦截可以在请求和响应中添加、修改或删除头信息,也可以重试请求或者记录请求和响应的日志等。 以下是一个简单的OkHttp拦截示例,它会在请求头中添加一个自定义的User-Agent信息: ```java public class UserAgentInterceptor implements Interceptor { private static final String USER_AGENT_HEADER = "User-Agent"; private final String userAgent; public UserAgentInterceptor(String userAgent) { this.userAgent = userAgent; } @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Request newRequest = request.newBuilder() .header(USER_AGENT_HEADER, userAgent) .build(); return chain.proceed(newRequest); } } ``` 在上面的示例中,我们创建了一个名为UserAgentInterceptor的拦截,它接收一个User-Agent字符串作为参数。在intercept方法中,我们首先获取当前的请求对象,然后使用Request.Builder添加一个自定义的User-Agent头信息,最后使用chain.proceed方法将请求传递给下一个拦截或者返回响应。 以下是一个使用上面定义的拦截的示例: ```java OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(new UserAgentInterceptor("MyApp/1.0")) .build(); ``` 在上面的示例中,我们创建了一个OkHttpClient对象,并使用addInterceptor方法添加了一个UserAgentInterceptor拦截。这样,在发送请求时,OkHttp会自动调用我们定义的拦截,并在请求头中添加一个自定义的User-Agent信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万子开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值