OkHttp深入理解(5)CallServerInterceptor
来源:互联网 发布:w3school sql 编辑:程序博客网 时间:2024/06/07 00:17
这是整个拦截器链中的最后一个拦截器,经过了前面拦截器进行的准备工作,在CallServerInterceptor中会真正向服务器发起请求。intercept方法的代码不多:
@Override public Response intercept(Chain chain) throws IOException { RealInterceptorChain realChain = (RealInterceptorChain) chain; 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) { // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100 // Continue" response before transmitting the request body. If we don't get that, return // what we did get (such as a 4xx response) without ever transmitting the request body. if ("100-continue".equalsIgnoreCase(request.header("Expect"))) { httpCodec.flushRequest(); realChain.eventListener().responseHeadersStart(realChain.call()); responseBuilder = httpCodec.readResponseHeaders(true); } if (responseBuilder == null) { // Write the request body if the "Expect: 100-continue" expectation was met. 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()) { // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection // from being reused. Otherwise we're still obligated to transmit the request body to // leave the connection in a consistent state. streamAllocation.noNewStreams(); } } httpCodec.finishRequest(); 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(); realChain.eventListener() .responseHeadersEnd(realChain.call(), response); int code = response.code(); if (forWebSocket && code == 101) { // Connection is upgrading, but we need to ensure interceptors see a non-null response body. 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; }
大致流程如下:
1. 写入请求头
2. 判断呢是否需要发送RequestBody,如果不需要,直接跳转到步骤5
3. 如果2满足,继续判断header中Expect域是否为100-continue,这个请求头字段的作用是在发送RequestBody前向服务器确认是否接受RequestBody,如果服务器不接受也就没有发送的必要了。有这个字段,相当于一次简单的握手操作,会等待拿到服务器返回的ResponseHeaders之后再继续,如果服务器接收RequestBody,会返回null。
4. 根据3的判断,如果RequestBuilder为null,说明Expect不为100-continue或者服务器同意接收RequestBody。这时就开始向流中写入RequestBody。
5. 读取响应头信息
6. 构建Response,写入原请求、握手情况、请求时间、得到结果的时间等
7. 构建响应体
8. 如果请求或者响应头要求close连接,进行断开
9. 针对204/205状态码处理
10. 返回Response
针对3中的Expect字段详解可以看看这段:
1、http 100-continue用于客户端在发送POST数据给服务器前,征询服务器情况,看服务器是否处理POST的数据,如果不处理,客户端则不上传POST数据,如果处理,则POST上传数据。在现实应用中,通过在POST大数据时,才会使用100-continue协议。
2、客户端策略。
1)如果客户端有POST数据要上传,可以考虑使用100-continue协议。加入头{“Expect”:”100-continue”}
2)如果没有POST数据,不能使用100-continue协议,因为这会让服务端造成误解。
3)并不是所有的Server都会正确实现100-continue协议,如果Client发送Expect:100-continue消息后,在timeout时间内无响应,Client需要立马上传POST数据。
4)有些Server会错误实现100-continue协议,在不需要此协议时返回100,此时客户端应该忽略。
3、服务端策略。
1)正确情况下,收到请求后,返回100或错误码。
2)如果在发送100-continue前收到了POST数据(客户端提前发送POST数据),则不发送100响应码(略去)。
CallServerInterceptor的整体逻辑不难。复杂的细节被封装到了HttpCodec实现类里,它有针对HTTP 1.1/HTTP2的两个实现类,而里面进行具体的流的写入/读取操作,又被封装到了okio库的BufferedSink等相关的类中,要深入下去工作量还很多。暂时就这样了。
至此针对OkHttp的拦截器的笔记就写完了,不容易唉。接下来有时间会继续记录一些诸如路由寻址、缓存具体实现等的细节。
- OkHttp深入理解(5)CallServerInterceptor
- Okhttp之CallServerInterceptor简单分析
- OKhttp源码解析---拦截器之CallServerInterceptor
- OkHttp深入理解(1)综述
- OkHttp深入理解(2)RetryAndFollowUpInterceptor
- OkHttp深入理解(4)ConnectInterceptor
- 深入理解Okhttp
- 深入理解OkHttp源码(一)——提交请求
- 深入理解OkHttp源码(二)——获取响应
- 深入理解OkHttp源码(三)——网络操作
- 深入理解OkHttp源码(四)——缓存
- OkHttp深入理解(3)BridgeInterceptor与CacheInterceptor
- 深入理解计算机系统(5)
- 深入理解JVM(5)
- OkHttp深入学习
- OkHttp源码深入解读
- 理解redo(5)深入学习RBA
- Java 集合深入理解(5):AbstractCollection
- Java中的锁 (2) 底层CAS
- 将Mat图像显示到MFC PictureControl控件上
- Service
- Linux重定向及nohup不输出的方法
- Could not load the Tomcat server configuration at \Servers\Tomcat v8.0 Server at localhost-config
- OkHttp深入理解(5)CallServerInterceptor
- JAX-RS 和 和 Spring 整合开发
- java栈映射表
- powershell的安装使用
- jquery和vue对比(二)
- 自定义jquery插件基本形式
- 这是从云栖大会指挥部发回的现场报道
- 正确选择PDF转CAD软件官方下载能够免费使用
- 泛型与枚举