相关

Android—网络编程之Http协议

Android—网络编程之OkHttp3整体结构了解以及使用

Android—网络编程之Okhttp3源码解析

Android—网络编程之Retrofit2整体结构了解以及+Okhttp3+rxjava2使用

Android—网络编程之Retrofit2源码分析

Android—网络编程之Socket编程(实例)

在这里为大家提供一种思路,看一款开源项目的时候,可以先看一下,这个开源框架包括那些类,哪些接口,根据注释大体了解一下各个类和接口的作用,这样有助于我们把握一个项目的全局架构,更好的理解一个好的开源框架。

OKHttp功能

大家应该都知道接口和抽象类的作用

  • 抽象类:用于模板设计,抽离共性,实现多态
  • 接口:用于功能的定制
那么okhttp中的接口都是些什么,定制了一些什么样的功能,可以一起来看一些(基于3.10.0版本)
  • Authenticator:响应服务器的身份验证,其实现类需要返回一个包含授权头的请求,也可以返回null,出发这种情况的调用者会接受这个响应!
  • Call:同步或异步执行一个请求,该请求能被取消,不能被执行两次!
  • Call.Factory:Call的工厂接口,以前的版本是Call的内部接口!
  • Callback:请求失败或成功的回调接口,只有两个方法:失败:onFailure(Call call, IOException e);成功:onResponse(Call call, Response response)。
  • Connection:返回HTTP、HTTPS或HTTPS+HTTP/2连接的套接字和流。连接可以直接指向源服务器或通过代理。这个类的典型实例是由HTTP客户端自动创建、连接和执行的。应用程序可以使用这个类来监视作为连接池成员的HTTP连接。
  • CookieJar:为HTTP cookie提供策略和持久性。策略(loadForRequest(HttpUrl url)):接受或拒绝cookie。持久性(saveFromResponse(HttpUrl url,List cookies)):保存cookie,内存,文件,数据库…
  • Dns:把主机名解析为IP地址的域名服务。大多数应用程序将使用默认的系统DNS服务,当然也可以自己实现来使用不同的DNS服务器,这个接口的实现必须是安全的并发使用。
  • EventListener.Factory:EventListener的工厂接口,将在3.11或 3.12版本完善这一系列的API,所有的启动/连接/获取事件最终都会收到一个匹配的结束/发布事件,或者成功的(非空参数),或者失败(非空的可转换的)的事件。
  • Interceptor:这就是OKHttp至关重要的拦截器接口了,观察、修改和潜在的短路请求,以及相应的响应。拦截器通常在在请求或响应中添加、删除或转换。
  • WebSocket:WebSocket的非阻塞式接口,管理web套接字的请求,发送,队列消息字节大小,取消和关闭。由其工厂类创建对象。
  • WebSocket.Factory:WebSocket的工厂接口。
通过以上接口的解析,我们了解到了OKHttp的大体功能,依附于这些功能接口,OKHttp是怎样实现的呢,下面我把OKHttp的类按照义务即他们在整体中担任的责任划分出了几个功能组:

网络客户端的功能搭建

通过上一篇HTTP的基础了解,我们知道利用HTTP通信需要设置请求头,对okhttp来说就是配置对象的属性,或者通过拦截器处理请求头和相应消息。而这些属性可以有以下类来实现。

  • Address:连接到源服务器的规范。主机名和端口。代理信息。对于安全连接,地址还包括SSL套接字工厂、主机名验证器和证书pinner。共享同一地址的HTTP请求也可以共享相同的连接。
  • Cache:对缓存的管理。
  • CacheControl:设置缓存策略。
  • CacheControl.Builder:构建一个Cache-Control请求头。builder模式,设置属性。
  • CertificatePinner:构建可信的证书。
  • CertificatePinner.Builder:构建一个已配置的证书
  • Challenge:配置一个安全的身份验证
  • CipherSuite:TLS密码组件。
  • ConnectionPool:连接池,管理HTTP和HTTP/2的链接以及重用的策略。
  • ConnectionSpec:指定在HTTP传输时的套接字连接的配置。对于https,这包括在协商安全连接时使用的TLS版本和加密组件。
  • ConnectionSpec.Builder:创建ConnectionSpec的对象,并设置其属性!
  • Cookie:cookie管理类
  • Cookie.Builder:实例化Cookie对象,但是Cookie的name, value, 和domain values必须在build()方法之前设置。
  • Credentials:创建HTTTP授权凭证的工厂
  • Dispatcher:执行异步请求时的策略。
  • EventListener:事件侦听器。扩展这个类以监视应用程序的HTTP调用的数量、大小和持续时间。(非最终API,将在3.11或3.12版本确定)

  • RFC:是一系列以编号排定的文件。文件收集了有关互联网相关信息,以及UNIX和互联网社区的软件文件。几乎所有的因特网标准都收录在RFC文件之中。

以上属性的配置都可以用OkHttpClient,OkHttpClient.Builder配置

  • OkHttpClient:实现的接口:Cloneable, Call.Factory, WebSocket.Factory。可以用来发送HTTP请求和读取响应的调用工厂。他适合创建单列,当创建单个OkHttpClient实例并将其用于所有的HTTP调用时,OkHttp执行得最好。这是因为每个客户机都有自己的连接池和线程池。重用连接和线程可以减少延迟并节省内存。相反,为每个请求创建客户端会浪费空闲池上的资源。OkHttp还使用了HTTP/2连接的守护线程。如果它们保持空闲,它们将自动退出。
  • OkHttpClient.Builder:创建OkHttpClient,设置OkHttpClient的一些属性。属性如下:
属性 类型 引用变量 设置方法
异步请求时的策略 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:一个HTTP请求。可以使用get或post方法,可以设置标记取消请求,可以设置此请求的cache-control头,已替换任何缓存控制头。
  • FormBody:继承RequestBody,表单请求封装。
  • FormBody.Builder:FormBody的内部类,创建FormBody对象并设置属性!
  • Handshake:TLS握手的记录。这个值对象描述了一个完成的握手。使用ConnectionSpec来设置新握手的策略。
  • Headers:单个HTTP消息的头字段。使用请求和对解释头的响应。这个类维护HTTP消息中的头字段的顺序。
  • Headers.Builder:Headers的内部类!创建Headers对象。
  • HttpUrl:一个统一资源定位器(URL),带有http或https的方案。使用这个类来编写和分解Internet地址。
  • HttpUrl.Builde:HttpUrl的内部类,创建HttpUrl对象并设置属性!
  • MediaType:RFC 2045媒体类型,用于描述HTTP请求或响应主体的内容类型。
  • MultipartBody:符合RFC 2387(1998年发布MIME Multipart /相关的内容类型)的请求体。
  • MultipartBody.Part:请求头(Headers)和请求体(RequestBody)的封装内部类。
  • ResponseBody:从源服务器到客户端应用程序的使用响应主体原始字节的一次性流。响应体必须被关闭:每个响应主体由一个有限的资源支持,比如套接字(实时网络响应)或一个打开的文件(用于缓存的响应)。如果未能关闭响应体,将会泄漏资源,并可能最终导致应用程序卡顿或崩溃。响应体只能使用一次。
  • Response:一个HTTP响应。响应体是一次性的。这个类实现Closeable。关闭它只是关闭它的响应主体。
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/7971914104-12 13:18:11.649 5065-5156/com.example.zcp.ok3test E/request connection: null04-12 13:18:11.649 5065-5156/com.example.zcp.ok3test E/request headers: User-Agent: oktest                                                                        Cache-Control: public, max-age=360004-12 13:18:12.299 5065-5156/com.example.zcp.ok3test E/Received response for: https://blog.csdn.net/zcpHappy/article/details/7971914104-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: oktest04-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/7971914104-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/request connection: null04-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/request headers: User-Agent: oktest                                                                         Cache-Control: public, max-age=360004-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/Received response for: https://blog.csdn.net/zcpHappy/article/details/7971914104-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: oktest04-12 13:25:13.174 5065-11442/com.example.zcp.ok3test E/response body: okhttp3.internal.http.RealResponseBody@4a854060

无网络,缓存中的响应输出

可以看到,配置缓存以后 请求到响应从651.625836毫秒下降到2.990045毫秒;当然配置缓存以后,在有网络的情况下也是使用的缓存

拼搏在技术道路上的一只小白And成长之路

更多相关文章

  1. Android保存数据几种常用方法解析
  2. Android 中插件的编写方法
  3. Android shape方法绘制图形的方法和属性解析
  4. 【Android Studio使用教程1】Android Studio导入项目的几种方法
  5. Android 中三种使用线程的方法
  6. Android 将从网络获取的数据缓存到私有文件
  7. Android 把从网络获取的图片缓存到内存中
  8. Android Activity onConfigurationChanged()方法 监听状态改变
  9. 第三部分:Android 应用程序接口指南---第一节:应用程序组件---第六

随机推荐

  1. findlibrary returned null产生的联想,And
  2. [置顶] Android(安卓)自定义View实现竖直
  3. Android项目开发,不能不了解的第三方库!(齐
  4. android实现观察者模式的几种方法
  5. Android的内存机制和常见泄漏情形
  6. Android(安卓)APN的设置问题--进一步讨论
  7. android工程下运行main方法的配置方法
  8. 史上最全的Android开发学习教程集锦【初
  9. Android工程 引用另外一个Android工程
  10. J2me游戏如何快速移植到Android(安卓)(2)