//从url里面获取cookie
//这个cookieJar是Okhttp上面设置的那个cookieJar
List<Cookie> cookies = cookieJar.loadForRequest(userRequest.url());
if (!cookies.isEmpty()) {
//将所有的cookie添加到cookie头
requestBuilder.header("Cookie", cookieHeader(cookies));
}
public final class BridgeInterceptor implements Interceptor {
/**
* 用来处理Cookie的保存和读取
*/
private final CookieJar cookieJar;
可以看到是在构造方法里面传入的
public BridgeInterceptor(CookieJar cookieJar) {
this.cookieJar = cookieJar;
}
可以看到是在RealCall中调用了这个构造方法
点击里面的cookieHeader看看
/** Returns a 'Cookie' HTTP request header with all cookies, like {@code a=b; c=d}. */
//用来将所有的Coookie转换成,key1=value1; key2=value2,例如:a=b; c=d
private String cookieHeader(List<Cookie> cookies) {
StringBuilder cookieHeader = new StringBuilder();
//遍历cookies列表
//相当于这个种形式 name=value;key=value
for (int i = 0, size = cookies.size(); i < size; i++) {
if (i > 0) {
cookieHeader.append("; ");
}
Cookie cookie = cookies.get(i);
cookieHeader.append(cookie.name()).append('=').append(cookie.value());
}
return cookieHeader.toString();
}
if (userRequest.header("User-Agent") == null) {
requestBuilder.header("User-Agent", Version.userAgent());
}
//这里调用下一个拦截器(最后一个拦截器返回回来的网络数据了)
//这段代码上面是处理器,下面是处理响应Response
Response networkResponse = chain.proceed(requestBuilder.build());
//从网络的相应中获取Cookie,这个方法里面或保存
HttpHeaders.receiveHeaders(cookieJar, userRequest.url(), networkResponse.headers());
-->点击跳转:
public static void receiveHeaders(CookieJar cookieJar, HttpUrl url, Headers headers) {
//如果没有设置cookie的代理,就直接返回
if (cookieJar == CookieJar.NO_COOKIES) return;
//从header中解析出cookie
List<Cookie> cookies = Cookie.parseAll(url, headers);
if (cookies.isEmpty()) return;
//然后调用保存方法
cookieJar.saveFromResponse(url, cookies);
}
-->点击跳转:查看Cookie.parseAll(url, headers)
public static List<Cookie> parseAll(HttpUrl url, Headers headers) {
List<String> cookieStrings = headers.values("Set-Cookie");
List<Cookie> cookies = null;
for (int i = 0, size = cookieStrings.size(); i < size; i++) {
Cookie cookie = Cookie.parse(url, cookieStrings.get(i));
if (cookie == null) continue;
if (cookies == null) cookies = new ArrayList<>();
cookies.add(cookie);
}
return cookies != null
? Collections.unmodifiableList(cookies)
: Collections.<Cookie>emptyList();
}
============================================
//根据网络的响应创建一个Builder,这和前面从请求体创建一个Builder类似
Response.Builder responseBuilder = networkResponse.newBuilder()
.request(userRequest);
if (transparentGzip
&& "gzip".equalsIgnoreCase(networkResponse.header("Content-Encoding"))
&& HttpHeaders.hasBody(networkResponse)) {
//在这里处理响应体是gzip类型的工作
//networkResponse.body().source():可以理解为就是输入流
//这里其实是一个包装设计模式
GzipSource responseBody = new GzipSource(networkResponse.body().source());
Headers strippedHeaders = networkResponse.headers().newBuilder()
.removeAll("Content-Encoding")
.removeAll("Content-Length")
.build();
responseBuilder.headers(strippedHeaders);
//这里用了一个包装类RealResponseBody,用来转换gzip响应体,这个后面再分析
//Okio.buffer可以理解为包装后的输入流
responseBuilder.body(new RealResponseBody(strippedHeaders, Okio.buffer(responseBody)));
}
//然后根据响应体Builder创建一个Response
return responseBuilder.build();
-->点击跳转:RealResponseBody
public final class RealResponseBody extends ResponseBody {
private final Headers headers;
private final BufferedSource source;
public RealResponseBody(Headers headers, BufferedSource source) {
this.headers = headers;
this.source = source;
}
@Override public MediaType contentType() {
String contentType = headers.get("Content-Type");
return contentType != null ? MediaType.parse(contentType) : null;
}
@Override public long contentLength() {
return HttpHeaders.contentLength(headers);
}
@Override public BufferedSource source() {
return source;
}
}
responseBody-->new GzipSource(networkResponse.body().source());
也就是我们本地在读取这个Gzip响应的时候会调用这个GzipSource的read方法
在这个方法里面吧真实的流给拆出来了(原来的流是GZip的流,这里把它拆成真实的流了)
public long read(Buffer sink, long byteCount) throws IOException {
if (byteCount < 0L) {
throw new IllegalArgumentException("byteCount < 0: " + byteCount);
} else if (byteCount == 0L) {
return 0L;
} else {
if (this.section == 0) {
this.consumeHeader();
this.section = 1;
}
if (this.section == 1) {
long offset = sink.size;
long result = this.inflaterSource.read(sink, byteCount);
if (result != -1L) {
this.updateCrc(sink, offset, result);
return result;
}
this.section = 2;
}
if (this.section == 2) {
this.consumeTrailer();
this.section = 3;
if (!this.source.exhausted()) {
throw new IOException("gzip finished without exhausting source");
}
}
return -1L;
}
}