再分析第二篇准备讲讲CallServerInterceptor。先OkHttp的RealConnection 说起,它主要是创建链接,创建链接分为两部分。分为createTunnel(这不是直接连接服务器,是链接的代理服务器)和connectSocket 通过socket直接连接,(socket 是实现http协议的api),主要分析createSocket吧。
/** Does all the work necessary to build a full HTTP or HTTPS connection on a raw socket. */
private void connectSocket(int connectTimeout, int readTimeout, Call call,
EventListener eventListener) throws IOException {
//proxy 的type分为直接连接,socket代理,http代理(一般Https,Ftp这种协议直接)
Proxy proxy = route.proxy();
//获取地址。Address 属于服务器的抽象定义,如果直连,这注意hostname和port。如果是代理还包含代理信息,SocketFactory,证书等。
Address address = route.address();
//如果是直连或者http代理,那么直接获取到socket,否则传进去new Socket,socketFactory() 获取的是
//DefaultSocketFactory 工厂。
rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP
? address.socketFactory().createSocket()
: new Socket(proxy);
eventListener.connectStart(call, route.socketAddress(), proxy);
rawSocket.setSoTimeout(readTimeout);
try {
// 正式连接到socket。
Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout);
} catch (ConnectException e) {
ConnectException ce = new ConnectException("Failed to connect to " + route.socketAddress());
ce.initCause(e);
throw ce;
}
// The following try/catch block is a pseudo hacky way to get around a crash on Android 7.0
// More details:
// https://github.com/square/okhttp/issues/3245
// https://android-review.googlesource.com/#/c/271775/
try {
// Okio 粉墨登出,一句话它是链接socket,然后从中读取byte,转换为buffer。source输入输入流,sink是读取流,source 我们用于写入header和requestBody信息。sink我们用于读取RequestBody的信息。
source = Okio.buffer(Okio.source(rawSocket));
sink = Okio.buffer(Okio.sink(rawSocket));
} catch (NullPointerException npe) {
if (NPE_THROW_WITH_NULL.equals(npe.getMessage())) {
throw new IOException(npe);
}
}
}
这里我们看到了非常重要的角色souce和sink。现在回到CallServerInterceptor.记住source 是读入流,sink属于写入流。
@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();
//注意前面的赋值在ConnectInterceptor 里面,HttpCodec 现在是HttpCodec1。
//到这里代表socket已经正式建立了连接。现在只需要通过Http协议与Server进行交互了。
long sentRequestMillis = System.currentTimeMillis();
realChain.eventListener().requestHeadersStart(realChain.call());
// public void writeRequest(Headers headers, String requestLine) throws IOException {
//if (state != STATE_IDLE) throw new IllegalStateException("state: " + state);
//sink.writeUtf8(requestLine).writeUtf8("\r\n");
//for (int i = 0, size = headers.size(); i < size; i++) {
// sink.writeUtf8(headers.name(i))
// .writeUtf8(": ")
// .writeUtf8(headers.value(i))
// .writeUtf8("\r\n");
// }
// sink.writeUtf8("\r\n");
// state = STATE_OPEN_REQUEST_BODY;
// }
// 通过我之前分析的拿到sink以后就可以写入RequestHeader 逻辑essay。
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);
}
// 100-continue 就是询问服务器是否处理Post数据,如果处理走下面的逻辑。
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);
// 对于POST,body为FormBody。写入RequetBody内容。
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();
}
}
//HttpCodc1 持有sink和source,完成请求。
httpCodec.finishRequest();
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
//实际这个是读取两次这个Response,这是地此意,读取到这个code=100
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
//code=100 代表读取正常,可以
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 {
//实际读取到ResposeBody。实际上openResonseBody也是通过source,read byte转换为ResponseBody,到这里我们就获取到结果了。返回到response。
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;
}
这里CallServerInterceptor就分析完了,没有分析太深入,后续有机会再次深入去了解吧,都是一些http请求的细节了。