OKHttp3

阅读: 评论:0

OKHttp3

OKHttp3

CallServerInterceptor

  • 系列
  • 前言
  • CallServerInterceptor
  • 总结

系列

OKHttp3–详细使用及源码分析系列之初步介绍【一】
OKHttp3–流程分析 核心类介绍 同步异步请求源码分析【二】
OKHttp3–Dispatcher分发器源码解析【三】
OKHttp3–调用对象RealCall源码解析【四】
OKHttp3–拦截器链RealInterceptorChain源码解析【五】
OKHttp3–重试及重定向拦截器RetryAndFollowUpInterceptor源码解析【六】
OKHttp3–桥接拦截器BridgeInterceptor源码解析及相关http请求头字段解析【七】
OKHttp3–缓存拦截器CacheInterceptor源码解析【八】
OKHttp3-- HTTP缓存机制解析 缓存处理类Cache和缓存策略类CacheStrategy源码分析 【九】
通过ConnectInterceptor源码掌握OKHttp3网络连接原理 呕心沥血第十弹【十】

前言

这篇文章将对OKHttp最后一个拦截器进行解析,总算快要结束了;上一篇文章讲到连接拦截器,即客户端已经与服务端进行了连接,那接下来的操作自然就是发送接收数据了,看看官网的注释

这是拦截器链上的最后一个拦截器,向服务器发起网络访问

那接下来就从源码看看它是如何实现发送请求数据,接收响应数据的

CallServerInterceptor

  @Override public Response intercept(Chain chain) throws IOException {RealInterceptorChain realChain = (RealInterceptorChain) chain;HttpCodec httpCodec = realChain.httpStream();StreamAllocation streamAllocation = realChain.streamAllocation();RealConnection connection = (RealConnection) tion();Request request = quest();long sentRequestMillis = System.currentTimeMillis();httpCodec.writeRequestHeaders(request);Response.Builder responseBuilder = null;if (HttpMethod.hod()) && 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();responseBuilder = adResponseHeaders(true);}if (responseBuilder == null) {// Write the request body if the "Expect: 100-continue" expectation was met.Sink requestBodyOut = ateRequestBody(request, request.body().contentLength());BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);request.body().writeTo(bufferedRequestBody);bufferedRequestBody.close();} 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 NewStreams();}}httpCodec.finishRequest();if (responseBuilder == null) {responseBuilder = adResponseHeaders(false);}Response response = quest(request).tion().handshake()).sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build();int code = de();if (forWebSocket && code == 101) {// Connection is upgrading, but we need to ensure interceptors see a non-null sponse = wBuilder().body(Util.EMPTY_RESPONSE).build();} else {response = wBuilder().body(httpCodec.openResponseBody(response)).build();}if ("close".quest().header("Connection"))|| "close".equalsIgnoreCase(response.header("Connection"))) {NewStreams();}if ((code == 204 || code == 205) && response.body().contentLength() > 0) {throw new ProtocolException("HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());}return response;}

这里代码我们分开看

第一部分:获取网络组件

    RealInterceptorChain realChain = (RealInterceptorChain) chain;HttpCodec httpCodec = realChain.httpStream();StreamAllocation streamAllocation = realChain.streamAllocation();RealConnection connection = (RealConnection) tion();Request request = quest();

这里通过拦截器链拿到了四个对象

  • HttpCodec : 封装I/O操作的对象,根据HTTP/1.x,HTTP/2版本,有两个对应的实现类Http1Codec、Http2Codec,可以简单理解为编码我们的请求,解码返回的响应
  • StreamAllocation:封装了一次网络操作需要的组件,为一个请求分配一个stream
  • RealConnection: 封装了一次Socket与服务器连接的对象,在OKHttp中将一次连接抽象为Connection,而它是其实现类
  • Request:封装用户的请求信息的对象

第二部分:发送请求

    long sentRequestMillis = System.currentTimeMillis();httpCodec.writeRequestHeaders(request);Response.Builder responseBuilder = null;if (HttpMethod.hod()) && request.body() != null) {if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {httpCodec.flushRequest();responseBuilder = adResponseHeaders(true);}if (responseBuilder == null) {Sink requestBodyOut = ateRequestBody(request, request.body().contentLength());BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);request.body().writeTo(bufferedRequestBody);bufferedRequestBody.close();} else if (!connection.isMultiplexed()) {NewStreams();}}httpCodec.finishRequest();

这部分主要是用来发送请求

  • 获取发送请求的时间戳,并将请求头信息写入
  • 检测是否为有body的请求方法,接下来有两个判断,分开讲述

第一个if判断的意思是:如果请求头中包含【Expect: 100- Continue】,那么就发送100-continue的请求,然后获取服务器的响应,看服务器是否同意接受请求体,如果服务器的响应码是HTTP_CONTINUE,即100,那这个responseBuilder 即为null

第二个判断:上面一个判断可以知道如果服务器同意接受请求体数据,那么responseBuilder 为null,接下来就构建输出流BufferedSink对象,将请求体数据写到其缓冲区

第三个判断:也就是responseBuilder 不为null,意思是服务器不同意接受该请求体,且同时这个连接不支持多路复用,也就是说这是一个Http/1.x的请求,那么我们就需要标记该连接不能再被复用,同时关闭相关的Socket

接下来就是将缓存区的数据写到Socket中,发送出去,到这里发送请求已经完成

第三部分:构建响应

    if (responseBuilder == null) {responseBuilder = adResponseHeaders(false);}Response response = quest(request).tion().handshake()).sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build();

首先获取响应头部信息,然后构建响应Response 对象

第四部分:处理响应

    int code = de();if (forWebSocket && code == 101) {// Connection is upgrading, but we need to ensure interceptors see a non-null sponse = wBuilder().body(Util.EMPTY_RESPONSE).build();} else {response = wBuilder().body(httpCodec.openResponseBody(response)).build();}if ("close".quest().header("Connection"))|| "close".equalsIgnoreCase(response.header("Connection"))) {NewStreams();}if ((code == 204 || code == 205) && response.body().contentLength() > 0) {throw new ProtocolException("HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());}return response;
  • 如果使用websocket且响应码是101,那么构建一个空响应体的response 对象;否则就根据响应体构建真正的响应对象
  • 如果请求头或者响应头部包含【Connection: close】,意味着该连接不需要保活,那就关闭该连接以及释放相应的资源
  • 如果响应码是204或者205,且响应体长度大于0,也就意味着该次请求成功,但是服务器只返回了响应行和响应头信息,没有响应体,可是这里拿到的响应体长度居然大于0,那就说明出问题了,所以需要抛出一个协议异常

总结

可以看到最后一个拦截器的代码比较简单,当然了你要是没有看前面的系列文章,可能会觉得有点懵;拦截器链上的五个拦截器分析完了,后续的文章将会介绍下OKHttp中有关WebSocket的知识点

本文发布于:2024-01-29 02:17:11,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170646583212013.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23