面试复习题--Okhttp

29 篇文章 0 订阅
28 篇文章 0 订阅

1、http的流程

  1. 使用DNS域名解析
  2. 发起TCP的3次握手
  3. 建立TCP连接后发起http请求;
  4. 服务器响应http请求,浏览器得到返回response;
  5. 浏览器解析response,并请求其它的资源(如js、css、图片等);
  6. 浏览器对页面进行渲染。

2、Https的流程

发起请求、验证身份、协商秘钥、加密会话,具体流程如下(此例子只有客户端对服务端的单向验证):

  1、客户端向服务端发起建立HTTPS请求。

  2、服务器向客户端发送数字证书。

  3、客户端验证数字证书,证书验证通过后客户端生成会话密钥(双向验证则此处客户端也会向服务器发送证书)。

  4、服务器生成会话密钥(双向验证此处服务端也会对客户端的证书验证)。

  5、客户端与服务端开始进行加密会话。

具体的步骤如下:

第一步:客户端向服务端发起请求

        1、客户端生成随机数R1 发送给服务端;

        2、告诉服务端自己支持哪些加密算法;

第二步:服务器向客户端发送数字证书

        1、服务端生成随机数R2;

        2、客户端支持的加密算法中选择一种双方都支持的加密算法(此算法用于后面的会话密钥生成)

        3、服务端生成把证书、随机数R2、会话密钥生成算法,一同发给客户端;

第三步:客户端验证数字证书。

        1、验证证书的可靠性,先用CA的公钥解密被加密过后的证书,能解密则说明证书没有问题,然后通过证书里提供的摘要算法进行对数据进行摘要,然后通过自己生成的摘要与服务端发送的摘要比对。

        2、验证证书合法性,包括证书是否吊销、是否到期、域名是否匹配,通过后则进行后面的流程

        3、获得证书的公钥、会话密钥生成算法、随机数R2

        4、生成一个随机数R3。

        5、根据会话秘钥算法使用R1、R2、R3生成会话秘钥。

        6、用服务端证书的公钥加密随机数R3并发送给服务端。

第四步:服务器得到会话密钥

        1、服务器用私钥解密客户端发过来的随机数R3

        2、根据会话秘钥算法使用R1、R2、R3生成会话秘钥

第五步:客户端与服务端进行加密会话

        1、客户端发送加密数据给服务端

              发送加密数据:客户端加密数据后发送给服务端。

        2、服务端响应客户端                     

              解密接收数据:服务端用会话密钥解密客户端发送的数据;                                                                加密响应数据:用会话密钥把响应的数据加密发送给客户端。

        3、客户端解密服务端响应的数据   

              解密数据:客户端用会话密钥解密响应数据;

3、Okhttp的流程

(1)、当我们通过OkhttpClient创立一个okHttpClient 、Request 、Call,并发起同步或者异步请求时;

(2)、okhttp会通过Dispatcher对我们所有的Call(RealCall实现类)进行统一管理,并通过execute()及enqueue()方法对同步或者异步请求进行执行
(3)、execute()及enqueue()这两个方法会最终调用RealCall中的getResponseWithInterceptorChain()方法,从阻拦器链中获取返回结果;
(4)、拦截器链中,依次通过ApplicationInterceptor应用拦截器、RetryAndFollowUpInterceptor(重定向阻拦器)、BridgeInterceptor(桥接阻拦器)、CacheInterceptor(缓存阻拦器)、ConnectInterceptor(连接阻拦器)、NetwrokInterceptor(网络拦截器)、CallServerInterceptor(请求阻拦器)对请求依次处理,与服务的建立连接后,获取返回数据,再经过上述阻拦器依次解决后,最后将结果返回给调用方。

4、Okhttp防抓包

  1、 使用Proxy.NO_PROXY进行防止抓包。
我们在使用OkHttp进行网络请求的时候防止Fiddler抓包可以简单的使用OkHttpClient.Builder中的builder.proxy(Proxy.NO_PROXY);方法就可以避免Fiddler基本抓包。

2、使用builder.proxySelector进行防止抓包。
因为第一种方法只能避免Fiddler基本抓包方式在OkHttp中还有一种方法可以防止抓包。

builder.proxySelector(new ProxySelector() {
            @Override
            public List<Proxy> select(URI uri) {
                return Collections.singletonList(Proxy.NO_PROXY);
            }

            @Override
            public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {

            }
        });
3、验证Https证书

这种方式要在app嵌入证书,以okhttp为例:当okhttp使用X509TrustManager对服务器证书进行校验时,如果服务器证书的 subjectDN 和嵌入证书的 subjectDN 一致,我们再进行签名内容 signature 的比对,如果不一致,抛出异常。示例代码如下:

  • 首先从本地读出证书,获取一个X509Certificate
val myCrt: X509Certificate by lazy {
    getCrt(R.raw.my_ca)
}

private fun getCrt(@RawRes raw: Int): X509Certificate {
    val certificateFactory = CertificateFactory.getInstance("X.509")
    val input = ApplicationContext.resources.openRawResource(raw)
    input.use {
        return certificateFactory.generateCertificate(input) as X509Certificate
    }
}
  • 检查服务器证书时对比嵌入的证书
private fun getTrustManagerInRelease(): X509TrustManager {

    return object : X509TrustManager {

        override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String?) {}
        override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
        override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String?) {
            val myCrt: X509Certificate = myCrt
            if (chain[0].subjectDN.name == myCrt.subjectDN.name) {
                if (!myCrt.signature!!.contentEquals(chain[0].signature)) {
                    throw SSLHandshakeException("签名不符!")
                }
            }
        }
    }
}
  • 将自定义的 SSLSocketFactory 和 X509TrustManager 将入到 okhttp 客户端
private fun getClient(ssl: SSLSocketFactory, trustManager: X509TrustManager): OkHttpClient {
    return OkHttpClient.Builder()
        .retryOnConnectionFailure(true)
        .proxy(Proxy.NO_PROXY)
        .sslSocketFactory(ssl, trustManager)
        .build()
}

5、拦截器

RetryAndFollowUpInterceptor(重试和重定向拦截器)
第一个接触到请求,最后接触到响应;负责判断是否需要重新发起整个请求;主要就是完成两件事情:重试与重定向
BridgeInterceptor(桥接拦截器)
补全请求,并对响应进行额外处理
CacheInterceptor(缓存拦截器)
请求前查询缓存,获得响应并判断是否需要缓存
ConnectInterceptor(链接拦截器)
与服务器完成TCP连接 (Socket)
CallServerInterceptor(请求服务拦截器)
与服务器通信;封装请求数据与解析响应数据(如:HTTP报文)
关联:https://blog.csdn.net/qq_45866344/article/details/125052085

6、优点

 (1)内置连接池,支持连接复用;
(2)支持gzip压缩响应体;
(3)通过缓存避免重复的请求;
(4)支持http2,对一台机器的所有请求共享同一个socket

7、连接池

OkHttp里面使用ConnectionPool实现连接池,而且默认支持5个并发KeepAlive,默认链路生命为5分钟。 双端队列Deque,双端都能进出,用来存储连接的。OkHttp框架采用的是Socket连接,底层涉及到Http协议的封装和解封,TLS/SSL安全协议的封装等;连接池主要涉及到几大类:ConnectionPool,RealConnection,StreamAllocation,ConnectionInterceptor;

1.ConnectionPool类:

该类是OkHttp的连接池,连接池可以有效地提高连接的使用效率;
主要涉及到添加,获取,删除连接等功能;

2.RealConection类:

RealConnection是Connection的是实现类,代表着一个真正的socket连接,RealConnection代表着客户端和服务器端已经有了一个通信链路;

3.StreamAllocation类:

StreamAllocation是外界使用Okhttp的连接的桥梁,通过newStream方法返回一个可使用的流,即HttpCodec实例,通过HttpCodec可以将输入数据封装成相应的Http协议的数据,然后通过socket的输出流发送出去,同时也可以通过socket的输入流读取数据并解析数据;

8、线程池

在OKHttp中,创建了一个阀值是Integer.MAX_VALUE的线程池,它不保留任何最小线程,随时创建更多的线程数,而且如果线程空闲后,只能多活60秒。所以也就说如果收到20个并发请求,线程池会创建20个线程,当完成后的60秒后会自动关闭所有20个线程。他这样设计成不设上限的线程,以保证I/O任务中高阻塞低占用的过程,不会长时间卡在阻塞上。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值