首先看调用接口intercept
@Override public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain) chain;
//获取HttpCodec
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;
//判断是否有请求实体的请求(不是GET请求)
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.
// 如果头部信息添加了"Expect: 100-continue",这个请求头字段的作用是在发送RequestBody前向服务器确认是否接受RequestBody,
// 如果服务器不接受也就没有发送的必要了。
// 有这个字段,相当于一次简单的握手操作,会等待拿到服务器返回的ResponseHeaders之后再继续,如果服务器接收RequestBody,会返回null。
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(true);
}
// 服务器同意接收,开始向流中写入RequestBody
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();
}
}
// 调用了sink.flush();
httpCodec.finishRequest();
// 读取头部信息、状态码等
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
//构建Response, 写入原请求,握手情况,请求时间,得到的响应时间
Response response = responseBuilder
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
//返回的状态码
int code = response.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 {
response = response.newBuilder()
.body(httpCodec.openResponseBody(response))
.build();
}
// 如果设置了连接关闭,则断开连接
if ("close".equalsIgnoreCase(response.request().header("Connection"))
|| "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
//HTTP 204(no content) 代表响应报文中包含若干首部和一个状态行,但是没有实体的主体内容。
//HTTP 205(reset content) 表示响应执行成功,重置页面(Form表单),方便用户下次输入
//这里做了同样的处理,就是抛出协议异常。
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、获取request、httpCodec等对象。
2、通过httpCodec发送状态行和头部数据到服务端。
3、判断是否是有请求实体的请求,如果是,判断当前是否有设置Expect: 100-continue请求头。
4、往流中写入请求实体内容。
5、读取服务器返回的头部信息、状态码等,构建responseBuilder对象并返回。
6、通过responseBuilder对象来构建response对象。
7、判断当前状态码,如果是100,则重新请求一次,得到response对象。
8、给Response对象设置body。
9、判断是否需要断开连接。
发送状态行和头部数据到服务端
@Override public void writeRequestHeaders(Request request) throws IOException {
// 获取状态行数据,返回类似"GET / HTTP/1.1"的字符串
String requestLine = RequestLine.get(
request, streamAllocation.connection().route().proxy().type());
writeRequest(request.headers(), requestLine);
}
/** Returns bytes of a request header for sending on an HTTP transport. */
public void writeRequest(Headers headers, String requestLine) throws IOException {
if (state != STATE_IDLE) throw new IllegalStateException("state: " + state);
// sink可看成是个封装了socket连接的输出流,将状态栏和头部数据输出到服务端
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;
}
这里使用了okio的Sink对象(可以看成封装了socket连接的输出流,详细可看okio)来将状态行和头部数据传到服务端。
读取服务器返回的头部信息、状态码并返回responseBuilder对象
@Override public Response.Builder readResponseHeaders(boolean expectContinue) throws IOException {
if (state != STATE_OPEN_REQUEST_BODY && state != STATE_READ_RESPONSE_HEADERS) {
throw new IllegalStateException("state: " + state);
}
try {
//获取响应行信息
StatusLine statusLine = StatusLine.parse(readHeaderLine());
// 构建Response.Builder对象
Response.Builder responseBuilder = new Response.Builder()
.protocol(statusLine.protocol)
.code(statusLine.code)
.message(statusLine.message)
.headers(readHeaders());
if (expectContinue && statusLine.code == HTTP_CONTINUE) {
return null;
} else if (statusLine.code == HTTP_CONTINUE) {
state = STATE_READ_RESPONSE_HEADERS;
return responseBuilder;
}
state = STATE_OPEN_RESPONSE_BODY;
return responseBuilder;
} catch (EOFException e) {
// Provide more context if the server ends the stream before sending a response.
IOException exception = new IOException("unexpected end of stream on " + streamAllocation);
exception.initCause(e);
throw exception;
}
}
获取响应行数据,然后用响应行的数据构建Response.Builder对象,如果状态码为100且expectContinue为true,则会返回个null对象。如果只是状态码为100,则直接返回个Response.Builder对象,返回后往下也会去处理100这个状态。
来源:CSDN
作者:finley_feng
链接:https://blog.csdn.net/finley_feng/article/details/104185715