Okhttp的浅层架构分析
Okhttp的责任链模式和拦截器分析
Okhttp之RetryAndFollowUpInterceptor拦截器分析
Okhttp之BridgeInterceptor拦截器分析
Okhttp之CacheInterceptor拦截器分析
Okhttp之ConnectInterceptor拦截器分析
Okhttp之网络连接相关三大类RealConnection、ConnectionPool、StreamAllocation
Okhttp之CallServerInterceptor拦截器分析
浅析okio的架构和源码实现
CallServerInterceptor,访问服务器的拦截器,是最后一个拦截器了,要做的事情就是跟服务器交互,把请求发送给服务器,同时拿到服务器返回的response:
public final class CallServerInterceptor implements Interceptor
@Override
public Response intercept(Chain chain) throws IOException {
//这些对象在前面的Interceptor都已经创建完毕
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());
//1. 写入请求头
//这个方法分析一下,这个httpCodec我们走http2.0分支的
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Response.Builder responseBuilder = null;
//检测一下是否是允许的请求方式,body不为空
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
//一个小知识点,关于"Expect: 100-continue"的
//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响应码(略去)。
//如果请求中存在“Expect:100-continue”标头,请在发送请求主体之前等待“HTTP / 1.1 100 Continue”响应。
// 如果我们没有得到,请返回我们得到的内容(例如4xx响应),不继续发送请求主体。
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
//flush请求头
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
//这个方法会进入等待,当后台返回100应答的时候responseBuilder 为空
//点进去就是调用了stream的takeHeaders()方法获取读到的header
responseBuilder = httpCodec.readResponseHeaders(true);
}
//2 写入请求体
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();
}
}
//关闭request输出
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();
//4 读取响应体
int code = response.code();
if (code == 100) {
// server sent a 100-continue even though we did not request one.
// try again to read the actual response
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) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
response = response.newBuilder()
.body(Util.EMPTY_RESPONSE)
.build();
} else {
//组织body
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
//标记noNewStreams
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;
}
}
//Http2Codec的writeRequestHeaders()方法
@Override public void writeRequestHeaders(Request request) throws IOException {
if (stream != null) return;
boolean hasRequestBody = request.body() != null;
//组装一下header
List<Header> requestHeaders = http2HeadersList(request);
//newStream方法是Http2Connection的,继续追踪下去
stream = connection.newStream(requestHeaders, hasRequestBody);
stream.readTimeout().timeout(chain.readTimeoutMillis(), TimeUnit.MILLISECONDS);
stream.writeTimeout().timeout(chain.writeTimeoutMillis(), TimeUnit.MILLISECONDS);
}
/**
* Returns a new locally-initiated stream.
* @param out true to create an output stream that we can use to send data to the remote peer.
* Corresponds to {@code FLAG_FIN}.
*/
//Http2Connection的newStream()方法
public Http2Stream newStream(List<Header> requestHeaders, boolean out) throws IOException {
return newStream(0, requestHeaders, out);
}
private Http2Stream newStream(
int associatedStreamId, List<Header> requestHeaders, boolean out) throws IOException {
boolean outFinished = !out;
boolean inFinished = false;
boolean flushHeaders;
Http2Stream stream;
int streamId;
synchronized (writer) {
synchronized (this) {
if (nextStreamId > Integer.MAX_VALUE / 2) {
shutdown(REFUSED_STREAM);
}
if (shutdown) {
throw new ConnectionShutdownException();
}
streamId = nextStreamId;
nextStreamId += 2;
stream = new Http2Stream(streamId, this, outFinished, inFinished, null);
flushHeaders = !out || bytesLeftInWriteWindow == 0L || stream.bytesLeftInWriteWindow == 0L;
if (stream.isOpen()) {
//这个new出来的stream也保存在streams里,是个map
//同时会返回赋值给Http2Codec的成员变量stream
//每次读到数据都会调用Http2Connection的readers()方法把数据存到相应的stream
streams.put(streamId, stream);
}
}
if (associatedStreamId == 0) {
//走着里,完成写header操作
writer.synStream(outFinished, streamId, associatedStreamId, requestHeaders);
} else if (client) {
throw new IllegalArgumentException("client streams shouldn't have associated stream IDs");
} else { // HTTP/2 has a PUSH_PROMISE frame.
writer.pushPromise(associatedStreamId, streamId, requestHeaders);
}
}
if (flushHeaders) {
writer.flush();
}
return stream;
}
网友评论