0%

Http 2.0和OkHttp

建议花钱,花钱可以少操心。购买的服务越低调越好,越高调的服务越容易被封。

简要介绍下Http2.0和我们经常接触的使用场景。在Android开发里通常是用OkHttp,分析了OkHttp的使用特点。

Http2.0

Http2.0的优点有多路复用等等。既然有优点,那么现在有多少地方用到了呢。Twitter,Facebook,Google都用上了。

怎么看访问的链接是否启用了Http2.0?

用Chrome的开发者工具可以看到请求,从request headers如果可以看到viewSource选项一般里面可以看到协议版本,一般是1.1,*如果没有viewSource选项可以默认认为是http2.0.另外,用上chrome的一个插件Http2.0/SPDY Indicator可以方便鉴别出来。可以看到淘宝网,腾讯首页都用上了http2.0,而百度还是1.1。这里并不是说百度垃圾,现在其实很多app请求还是用的是http1.1,可能原因是旧服务器迁移和维护的成本。*

一般现在的CDN和云存储都支持Http2.0,但不一定是默认启动的。可以在配置里找下启用。

Okhttp

支持Http2.0是客户端和服务端两方面都得支持。OkHttp现在是支持的,本身会通过连接去判断,可以自行去看源码,是在Connect建立连接的时候判断,值得一提的是,目前OKHttp仅支持在https请求下使用HTTP 2.0。

拦截器

Interceptor,这是OkHttp里面一个很好用的东西。你可以给请求都加上log,请求重试,对于一套比较相似的网络请求加上共同的请求头。

这里有个关键的东西是,它不仅仅针对了请求发出,也可以针对请求结果。请求结果!这可不是简单的加个打印,还有像重试这种骚操作。其实我们还经常看这种请求失败后自己去写一堆重试代码,既然你用了OkHttp,这不是脱裤子放屁——多此一举吗!

拦截器的接口设计,OkHttp的代码风格和Google很像,在接口中定义接口,从Google官方中的MVP sample中也可以看到这种设计,Contrate,你懂的(ฅ´ω`ฅ) 。这里的这种设计也有它独特的用法,比如——责任链模式。

来点真的,看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Observes, modifies, and potentially short-circuits requests going out and the corresponding
* responses coming back in. Typically interceptors add, remove, or transform headers on the request
* or response.
*/
public interface Interceptor {
Response intercept(Chain chain) throws IOException;

interface Chain {
Request request();

Response proceed(Request request) throws IOException;
}
}

首先,找到Intercepter使用的地方

这里插一个东西,OkHttpClient有没有必要写成单例?这里在很长一段时间里我都认为是需要的。为了减少创建对象,避免重复创建资源等balabala,但是从这里interceptor添加源码的角度来讲呢,其实如果你用到的请求资源,配置这些,interceptor这些一样的话,只用一个okhttpclient是可以的。如果不一样其实没必要,毕竟如果很多模块之间公用,这里会共用这些interceptor。

通过使用这些Intercepter的调用可以找到RealInterceptorChain,chain的唯一实现类,这个名字链,其实也说明了这是一个链式调用。通过这种接口里面定义接口的方式,方便,了然地实现了责任链调用。

调用方式

RealCall

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(client.cookieJar()));
interceptors.add(new CacheInterceptor(client.internalCache()));
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(forWebSocket));

Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());

return chain.proceed(originalRequest);
}

这里新建了一个RealInterceptorChain,关键在#proceed方法

1
2
3
4
5
6
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);

可以看到

这里新建了下一个RealInterceptorChain,next,从index中拿出第一个interceptor,然后把next这个chain传递给interceptor处理。责任链调用,我感觉这里有一个小技巧,如果自己写,会怎么去写这个责任链呢。

1.初始调用

在外部,新建了一个chain(把interceptor列表穿进去),调用了proceed方法

2.内部调用下一个

内部的proceed方法新建一个chain,然后取出下一个interceptor(index +1),调用下一个的方法,

其实这边chain’的index和interceptor的index并不一样,需要跳出这个index一样的禁锢。

如果我们去写一个责任链感觉也可以用这个方法写。

这边还有一个技巧,怎么保证interceptor都会调用proceed方法呢,看到interceptor接口的intercept方法,这边必须返回一个response,如果你要获得response,就调用了proceed方法