美文网首页
网络 OkHttp 面试

网络 OkHttp 面试

作者: Android_冯星 | 来源:发表于2020-04-15 17:26 被阅读0次

1. OkHttp对于网络请求都有哪些优化

  • 通过连接池来减少请求延时
  • 无缝支持GZIP来减少数据流量
  • 缓存响应数据来减少重复的网络请求
  • 可以从很多常用的连接问题中自动恢复

2. OkHttp框架中都用到了哪些设计模式

  • 外观模式
  • 建造者模式(OkHttpClient,Request等各种对象的创建)
  • 原型模式
  • 责任链模式(拦截器)
  • 简单工厂(CacheStrategy#Factory)

3. 为什么response.body().string() 只能调用一次

我们可能习惯在获取到Response对象后,先response.body().string()打印一遍log,再进行数据解析,却发现第二次直接抛异常,其实直接跟源码进去看就发现,通过source拿到字节流以后,直接给closeQuietly悄悄关闭了,这样第二次再去通过source读取就直接流已关闭的异常了。

public final String string() throws IOException {
    BufferedSource source = source();
    try {
      Charset charset = Util.bomAwareCharset(source, charset());
      return source.readString(charset);
    } finally {
      //这里讲resource给悄悄close了
      Util.closeQuietly(source);
    }
  }

4. 如何实现网络请求

OkHttp3的最底层是Socket,而不是URLConnection,它通过Platform的Class.forName()反射获得当前Runtime使用的socket库。

5. 断点续传

step 1:判断检查本地是否有下载文件,若存在,则获取已下载的文件大小 downloadLength,若不存在,那么本地已下载文件的长度为 0
step 2:获取将要下载的文件总大小(HTTP 响应头部的 content-Length)
step 3:比对已下载文件大小和将要下载的文件总大小(contentLength),判断要下载的长度
step 4:再即将发起下载请求的 HTTP 头部中添加即将下载的文件大小范围(Range: bytes = downloadLength - contentLength)

6. Dispatcher

  • 记录同步任务、异步任务及等待执行的异步任务。
  • 线程池管理异步任务。
  • 发起/取消网络请求API:execute、enqueue、cancel。

OkHttp设置了默认的最大并发请求量 maxRequests = 64 和单个host支持的最大并发量 maxRequestsPerHost = 5。

7. RetryAndFollowUpInterceptor

负责失败自动重连和必要的重定向

  • 协议问题,不能重试。
  • 安全问题,不要重试。
  • 如果是超时问题,并且请求没有被发送,可以重试,其他的就不要重试了。
  • 没有更多的可以使用的路由,不能重试
  • 如果我们在配置OkHttpClient中配置retryOnConnectionFailure属性为false,表明拒绝失败重连,那么这里返回false

8. BridgeInterceptor

  • 负责把用户构造的请求转换为发送到服务器的请求 、把服务器返回的响应转换为用户友好的响应,是从应用程序代码到网络代码的桥梁

  • 设置内容长度,内容编码

  • 设置gzip压缩,并在接收到内容后进行解压。省去了应用层处理数据解压的麻烦

  • 添加cookie

  • 设置其他报头,如User-Agent,Host,Keep-alive等。其中Keep-Alive是实现连接复用的必要步骤

9. CacheInterceptor

    1. 通过Request尝试到Cache中拿缓存(里面非常多流程),当然前提是OkHttpClient中配置了缓存,默认是不支持的。
    1. 根据response,time,request创建一个缓存策略,用于判断怎样使用缓存。
    1. 如果缓存策略中设置禁止使用网络,并且缓存又为空,则构建一个Resposne直接返回,注意返回码=504
    1. 缓存策略中设置不使用网络,但是有缓存,直接返回缓存
    1. 接着走后续过滤器的流程,chain.proceed(networkRequest)
    1. 当缓存存在的时候,如果网络返回的Resposne为304,则使用缓存的Resposne。
    1. 构建网络请求的Resposne
    1. 当在OKHttpClient中配置了缓存,则将这个Resposne缓存起来。
    1. 缓存起来的步骤也是先缓存header,再缓存body。
    1. 返回Resposne。
    1. OkHttpClient源码中支持GET形式的缓存。

10. ConnectInterceptor

1.尝试当前连接是否可以复用。
2.尝试连接池中找可以复用的连接
3.切换路由,继续在连接中尝试找可以复用的连接
4.以上都没有则new一个新的。
5.新的连接放入连接池
5.建立连接,开始握手

11. CallServerInterceptor

1.先写入请求Header
2.如果请求头的Expect: 100-continue时,只发送请求头,执行3,不然执行4
3.根据后台返回的结果判断是否继续请求流程
4.写入请求体,完成请求
5.得到响应头,构建初步响应
6.构建响应体,完成最终响应
7.返回响应

12. addInterceptor与addNetworkInterceptor的区别

二者通常的叫法为应用拦截器和网络拦截器,从整个责任链路来看,应用拦截器是最先执行的拦截器,也就是用户自己设置request属性后的原始请求,而网络拦截器位于ConnectInterceptor和CallServerInterceptor之间,此时网络链路已经准备好,只等待发送请求数据。

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);
  }

总结

image.png

https://juejin.im/post/5e59be00f265da57455b4709

https://www.jianshu.com/p/b32d13655be7

相关文章

网友评论

      本文标题:网络 OkHttp 面试

      本文链接:https://www.haomeiwen.com/subject/tnytvhtx.html