在这里为大家提供一种思路,看一款开源项目的时候,可以先看一下,这个开源框架包括那些类,哪些接口,根据注释大体了解一下各个类和接口的作用,这样有助于我们把握一个项目的全局架构,更好的理解一个好的开源框架。
网络客户端的功能搭建
通过上一篇HTTP的基础了解,我们知道利用HTTP通信需要设置请求头,对okhttp来说就是配置对象的属性,或者通过拦截器处理请求头和相应消息。而这些属性可以有以下类来实现。
EventListener:事件侦听器。扩展这个类以监视应用程序的HTTP调用的数量、大小和持续时间。(非最终API,将在3.11或3.12版本确定)
RFC:是一系列以编号排定的文件。文件收集了有关互联网相关信息,以及UNIX和互联网社区的软件文件。几乎所有的因特网标准都收录在RFC文件之中。
以上属性的配置都可以用OkHttpClient,OkHttpClient.Builder配置
属性 | 类型 | 引用变量 | 设置方法 |
---|---|---|---|
异步请求时的策略 | Dispatcher | dispatcher | 构造里面默认初始化;也可以dispatcher(Dispatcher dispatcher) 设置 |
HTTP代理 | Proxy | proxy | proxy(@Nullable Proxy proxy)方法设置 |
客户端配置的协议集合 | List | protocols | 构造默认为http/1.1和h2的集合;protocols(List protocols)方法设置,目前支持以上两种协议。 |
套接字配置集合 | List | connectionSpecs | 默认包含一个TLS链接和一个未加密的链接;connectionSpecs(List connectionSpecs)方法设置。 |
配置的拦截器集合 | List | interceptors | addInterceptor(Interceptor interceptor)方法设置拦截器,可以调用多次。 |
单个网络请求和响应的拦截器列表 | List | networkInterceptors | addNetworkInterceptor(Interceptor interceptor)配置使用 。 |
事件侦听器工厂对象 | EventListener.Factory | eventListenerFactory | eventListener(EventListener eventListener)方法转换设置;eventListenerFactory(EventListener.Factory eventListenerFactory)方法直接设置。 |
设置指定的代理选择策略 | ProxySelector | proxySelector | 默认使用系统范围的代理选择器;proxySelector(ProxySelector proxySelector)方法设置。 |
接收传入HTTP响应的cookie并提供其处理程序 | CookieJar | cookieJar | 默认为NULL;cookieJar(CookieJar cookieJar) 设置。 |
设置用于读取和写入缓存响应的响应缓存 | Cache;InternalCache | cache;internalCache | cache(@Nullable Cache cache)方法设置。setInternalCache(@Nullable InternalCache internalCache)。(Cache类内部实现了InternalCache接口) |
创建连接的套接字工厂 | SocketFactory | socketFactory | 默认使用系统的套接字工厂;socketFactory(SocketFactory socketFactory)方法设置。 |
安全HTTPS连接的套接字工厂 | SSLSocketFactory | sslSocketFactory | 默认使用系统自带的;sslSocketFactory(SSLSocketFactory sslSocketFactory)或sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)方法设置,最好使用后者。 |
从Java构建的TLS api中返回的原始数组计算有效的证书链。 | CertificateChainCleaner | certificateChainCleaner | 在设置Https的套接字工厂时被设置。 |
HTTPS链接请求主机名与响应证书的验证器 | HostnameVerifier | hostnameVerifier | 默认设置OkHostnameVerifier的对象;hostnameVerifier(HostnameVerifier hostnameVerifier)方法设置。 |
约束哪些证书可信任的证书pinner | CertificatePinner | certificatePinner | 构造器中初始化了一个pinne;certificatePinner(CertificatePinner certificatePinner)设置。 |
响应代理服务器身份验证器 | Authenticator | proxyAuthenticator | proxyAuthenticator(Authenticator proxyAuthenticator) |
响应源服务器的身份验证器。 | Authenticator | authenticator | authenticator(Authenticator authenticator) |
回收HTTP和HTTPS连接的连接池 | ConnectionPool | connectionPool | 默认使用新的连接池;也可以用connectionPool(ConnectionPool connectionPool)方法设置。 |
查找主机名IP地址的DNS服务 | Dns | dns | 不设置使用一个默认的DNS;用dns(Dns dns)设置自定义dns。 |
例如:下面就是一个基本的客户端配置
OkHttpClient okHttpClient = new OkHttpClient.Builder()
//缓存配置
.cache(new Cache(new File(MainActivity.this.getCacheDir(),"test_cache"),1024*1024*1024))
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
return null;
}
})//设置拦截器 可以对请求和响应做处理,比如缓存配置,打印响应流
// .addNetworkInterceptor()同上
.retryOnConnectionFailure(true)//开启失败重连
// .authenticator()响应服务器的身份验证,可以为NULL
// .certificatePinner() 配置证书
// .connectionPool() 配置连接复用池 , 默认5个 5分钟
// .connectionSpecs() 链接策略。默认包含一个TLS链接和一个未加密的链接
// .cookieJar() cookie 管理 默认为null
// .dispatcher()异步请求时的策略 默认已经初始化
// .dns()查找主机名IP地址的DNS服务 默认使用框架自带的DNS,也可以自己实现
// .followRedirects() 设置是否可以重定向 默认开启
// .followSslRedirects()从HTTPS到HTTP和从HTTP到HTTPS的重定向,默认遵循协议重定向
// .hostnameVerifier()HTTPS链接请求主机名与响应证书的验证器
// .pingInterval()设置此客户机发起的HTTP/2和web套接字ping之间的间隔。用它来自动发送ping帧,
// 直到连接失败或关闭。这使连接存在,并可检测连接性故障。
// .protocols()客户端配置的协议集合 默认为http/1.1和h2的集合
// .proxy() HTTP代理
// .readTimeout()设置新连接的默认读取超时。值0表示没有超时,否则。当转换为毫秒时,值必须在1到Integer.MAX_VALUE之间。
// .socketFactory() 默认使用系统的套接字工厂
// .sslSocketFactory() 同上
// .writeTimeout(10, TimeUnit.SECONDS)设置新连接的默认写入超时。值0表示没有超时,否则。当转换为毫秒时,值必须在1到Integer.MAX_VALUE之间。
.build();
基本的属性已经完成配置,就到了真正发起网络请求了,下面的就属于请求功能类了
Request request = new Request.Builder()
.url("http://c.3g.163.com/")//可以是string字符串,也可以是URL 或是一个HttpUrl
// .addHeader()添加请求头
// .header() 同上 方式不一样
// .headers()同上 方式不一样
// .cacheControl()配置请求时的缓存指令
// .delete() 请求时的方法
// .delete(new RequestBody() {
// @Nullable
// @Override
// public MediaType contentType() {
// return null;
// }
//
// @Override
// public void writeTo(BufferedSink sink) throws IOException {
//
// }
// }) 同上
.get() //同上
// .head() //同上
// .method() //同上 自己配置请求方法 和 请求体
// .patch()同上
// .post()同上
// .put()同上
// .removeHeader() 移除请求头
// .tag() 给此请求配置标记,通过此标记可以取消此请求
.build();
okHttpClient.newCall(request)
// .execute()//同步请求
.enqueue(new Callback() { //异步请求 有回调
@Override
public void onFailure(Call call, IOException e) {
//请求失败回调方法
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//请求成功回掉方法
}
});
Route:连接到抽象源服务器的具体路由。在创建连接时,可以有多个选择:
1.HTTP代理:可以为客户端显式地配置代理服务器。否则将使用代理选择器。它可以返回多个代理来尝试。
2.IP地址:是否直接连接到源服务器或代理,打开套接字需要一个IP地址。DNS服务器可能会返回多个IP地址来尝试。
每个路径都是这些选项的特定选择。
WebSocketListener:WebSocket连接时的一些监听。
至此,我们结合框架中的类和功能接口,对okhttp框架的使用完整的梳理了一遍,这样我也有了深刻的印象,当我们需要怎样配置就可以怎样配置了。一个简单的网络请求(例子)。
//缓存目录
cache = new Cache(new File(this.getCacheDir(),"test_cache"),1024*1024*1024);
//配置缓存策略
cacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//request = request.newBuilder().header("Cache-Control","public, max-age=3600").build(); 可以在这个地方配置 ,也可以在下面request配置
if(!isNetworkAvailable(MainActivity.this)){
request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
}
Response response = chain.proceed(request);
String cacheControl = request.cacheControl().toString();
if(isNetworkAvailable(MainActivity.this)){
return response.newBuilder()
.header("Cache-Control",cacheControl)
.header("User-Agent","oktest")
.removeHeader("Pragma")
.build();
}else {
return response.newBuilder()
.header("Cache-Control","public, " + CACHE_CONTROL_CACHE)
.header("User-Agent","oktest")
.removeHeader("Pragma")
.build();
}
}
};
//打印请求头 url;打印响应头 响应时间 响应体
logInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Log.e("Sending request",request.url().toString());
Log.e("request connection",chain.connection()+"");
Log.e("request headers",request.headers().toString());
Response response = chain.proceed(request);
long t2 = System.nanoTime();
Log.e("Received response for",response.request().url().toString());
Log.e("response time",(t2 - t1) / 1e6d+"毫秒");
Log.e("response headers",response.headers().toString());
Log.e("response body",response.body().toString());
//在这里也可以对response.body()操作处理
return response;
}
};
OkHttpClient okHttpClient = new OkHttpClient.Builder()
//缓存配置
.cache(cache)
.addInterceptor(cacheInterceptor)//设置拦截器 可以对请求和响应做处理,比如缓存配置,打印响应流
.addNetworkInterceptor(cacheInterceptor)//同上
.addInterceptor(logInterceptor)
.retryOnConnectionFailure(true)//开启失败重连
.build();
Request request = new Request.Builder()
.url("https://blog.csdn.net/zcpHappy/article/details/79719141")//可以是string字符串,也可以是URL 或是一个HttpUrl
.header("User-Agent", "oktest") //同上 方式不一样
.get() //同上
.build();
okHttpClient.newCall(request)
// .execute()//同步请求
.enqueue(new Callback() { //异步请求 有回调
@Override
public void onFailure(Call call, IOException e) {
//请求失败回调方法
tvShow.setText(e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
//请求成功回掉方法
// String responseString = response.body().string();
InputStream inputStream = response.body().byteStream();
final StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line;
try{
while ((line = bufferedReader.readLine())!=null){
stringBuilder.append(line+"\n");
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
inputStream.close();
}catch (Exception eInput){
eInput.printStackTrace();
}
}
runOnUiThread(new Runnable() {
@Override
public void run() {
tvShow.setText(stringBuilder.toString());
}
});
}
});
下面是有网络的情况下 请求头 响应头 输出情况
04-12 13:18:11.649 5065-5156/com.example.zcp.ok3test E/Sending request: https://blog.csdn.net/zcpHappy/article/details/79719141
04-12 13:18:11.649 5065-5156/com.example.zcp.ok3test E/request connection: null
04-12 13:18:11.649 5065-5156/com.example.zcp.ok3test E/request headers: User-Agent: oktest
Cache-Control: public, max-age=3600
04-12 13:18:12.299 5065-5156/com.example.zcp.ok3test E/Received response for: https://blog.csdn.net/zcpHappy/article/details/79719141
04-12 13:18:12.299 5065-5156/com.example.zcp.ok3test E/response time: 651.625836毫秒
04-12 13:18:12.299 5065-5156/com.example.zcp.ok3test E/response headers: Server: openresty
Date: Thu, 12 Apr 2018 05:18:12 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=20
Set-Cookie: uuid_tt_dd=10_9767942580-1523510292191-844897; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn.net;
Set-Cookie: dc_session_id=10_1523510292191.777942; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn.net;
Vary: Accept-Encoding
Strict-Transport-Security: max-age= 31536000
Cache-Control: public, max-age=3600
User-Agent: oktest
04-12 13:18:12.299 5065-5156/com.example.zcp.ok3test E/response body: okhttp3.internal.http.RealResponseBody@4a7dcc80
有网络响应体截图:
这部分是无网络情况下使用缓存,请求头 响应头输出情况
04-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/Sending request: https://blog.csdn.net/zcpHappy/article/details/79719141
04-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/request connection: null
04-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/request headers: User-Agent: oktest
Cache-Control: public, max-age=3600
04-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/Received response for: https://blog.csdn.net/zcpHappy/article/details/79719141
04-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/response time: 2.990045毫秒
04-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/response headers: Server: openresty
Date: Thu, 12 Apr 2018 05:18:12 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=20
Set-Cookie: uuid_tt_dd=10_9767942580-1523510292191-844897; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn.net;
Set-Cookie: dc_session_id=10_1523510292191.777942; Expires=Thu, 01 Jan 2025 00:00:00 GMT; Path=/; Domain=.csdn.net;
Vary: Accept-Encoding
Strict-Transport-Security: max-age= 31536000
Cache-Control: public, max-age=3600
User-Agent: oktest
04-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/response body: okhttp3.internal.http.RealResponseBody@4a854060
无网络,缓存中的响应输出
可以看到,配置缓存以后 请求到响应从651.625836毫秒下降到2.990045毫秒;当然配置缓存以后,在有网络的情况下也是使用的缓存