一、概述

最近想尝试写一个关于网络请求的系列文章,将网络请求的基础、使用及网络框架的学习分析总结以下,大致准备从以下几个方面分析:

  1. 网络请求的基础
  2. HTTP请求方式和报文解析
  3. Cookie 和 Session的理解与使用
  4. HTTP Cache缓存机制
  5. 封装网络请求
  6. TCP 和 Socket

HTTP的缓存机制,对于Web端的开发人员可能会比较熟悉,可作为移动端的开发使用的是限量的流量,所以对缓存和减少流量的要求更为需要,不过好在平时我们使用的网络框架都封装了如何设置缓存的方法,但从学习的角度还是要知道Http的协议是如何缓存文件和如何更新信息的。

二、缓存介绍

相信从缓存的名字上可以理解,及时保存已获取的数据下次直接使用,减少对服务器的请求和网络的消耗,看看缓存的执行流程:

  1. 程序第一次请求数据首先去缓存文件中,根据请求的url查询是否存在返回信息,如果存在则直接返回
  2. 如果缓存中没有数据,则直接去服务器读取数据,并携带服务器设定的缓存机制
  3. 获取数据显示后,根据设定的缓存机制保存请求的数据

三、缓存的分类可控制

  • 强制缓存:当本地有缓存文件切未失效时直接加载缓存,否则去网络获取并缓存

  • 对比缓存:首先读取本地缓存文件的标志,将此标志发送到服务端,服务端验证缓存数据是否失效,如果未失效返回304,则客户端会直接读取缓存文件,如果失效则返回新的数据和缓存配置

对比缓存又可以分为:Last-Modified  /  If-Modified-Since 和 Etag  /  If-None-Match 成对配合设置缓存;下面会详细介绍客户端和服务器如何实现缓存机制的。

  • Cache-control:Http的缓存主要利用Header里的Cache-control字段来控制,包含以下字段
  1. private:只有客户端缓存
  2. public:客户端和服务器端都可以缓存
  3. max-age:缓存的过期时间,当参过这个时间缓存就会失效
  4. no-Cache:需要数据对比验证缓存数据是否有效
  5. no-store:不进行缓存
  • 强制缓存实现

  1. 强制缓存的实现比较简单,是靠服务端返回的max-age设置的有效期控制,只要在设定的有效期之内数据均有效,且直接加载数据
  • 比较缓存实现
  1. Last-Modified  /  If-Modified-Since:根据修改的时间确定数据是否刷新

(1) Last-Modified :首次请求时服务端返回的Head中包含此字段,值为最新修改如期,客户端收到后储存信息
(2) If-Modified-Since:之后Request的Header中包含字段,并传递上次保存的日期
(3) 服务端收到请求后比较上传的修改日期与服务端的修改日期,确定数据是否更新

2、Etag  /  If-None-Match:服务器端的资源标志,用来对比缓存

(1)Etag  :客户端第一次请求时会返回资源的Etag,客户端收到后储存数据
(2)If-None-Match:下次请求时会在Header的If-None-Match中携带Etag
(3)服务端收到Etag后进行对比,确定时返回304还是新资源

四、okHttp中缓存的使用

  • 创键缓存文件夹及Cache
val file = File(activity!!.externalCacheDir.absolutePath + File.separator + "cache")
val cache = Cache(file, 1021 * 1024 * 10)
  • HTTP配置缓存
val okHttpClient = OkHttpClient.Builder().addInterceptor(CacheInterceptor()).cache(cache).build()val request = Request.Builder().url(url).build()var response = okHttpClient.newCall(request).execute()
System.out.println("Body Response = " + response.body().toString())
System.out.println("Cache Response = " + response.cacheResponse())
System.out.println("NetWork Response = " + response.networkResponse())
response.body()?.close()
var responseCache = okHttpClient.newCall(request).execute()
System.out.println("Body Response = " + responseCache.body().toString())
System.out.println("NetWork Response = " + responseCache.networkResponse())
System.out.println("Cache Response = " + responseCache.cacheResponse())
responseCache.body()?.close()
  • 两次请求后的数据输出为

  • 查看服务器的缓存时间为:3600 s(有效时间)

  • 再次获取时发现确实只从缓存读取

  • 那如果此时我们就是想从网络获取呢?使用 Cache-Control 策略
val request = Request.Builder().cacheControl(CacheControl.FORCE_NETWORK)  // 强制使用网络请求.url(url).build()
  • 此时输出的:

  • 查看缓存文件
  1. 手机文件夹 Android/data/com.***/cache/

2、查看缓存的文件信息

五、缓存拦截器 (Interceptor)

在拦截器中会获取请的的Request 和 返回的 Response ,我们可以在发起请求或接收结果时修改Header,实现想要的功能

  • 创建 Interceptor的实现类,并重写intercept方法(实现有网和无网不同的缓存)
public class CacheInterceptor implements Interceptor {@Overridepublic Response intercept(Chain chain) throws IOException {Request request = chain.request();  // 获取请求的Requestif (NetworkConnectionUtils.INSTANCE.isNetworkConnected(AppUtils.INSTANCE.getContext())) {// 有网络时, 缓存10秒钟int maxAge = 10;request = request.newBuilder()  // 修改Request 的Header.removeHeader("User-Agent").header("User-Agent", HttpUtils.INSTANCE.getUserAgent()).build();Response response = chain.proceed(request);  // 获取返回的Responsereturn response.newBuilder()    // 修改Response 的Header.removeHeader("Pragma").removeHeader("Cache-Control").header("Cache-Control", "public, max-age=" + maxAge) // 设置Cache-Control .build();} else {// 无网络时,缓存为4周int maxStale = 60 * 60 * 24 * 28;request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE)// 强制使用缓存.removeHeader("User-Agent").header("User-Agent", HttpUtils.INSTANCE.getUserAgent()).build();Response response = chain.proceed(request);return response.newBuilder().removeHeader("Pragma").removeHeader("Cache-Control").header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale).build();}}
}
  • 请求中添加拦截
.addInterceptor(CacheInterceptor())

到此,缓存机制和okhttp配置缓存介绍完了,所有信息都是在Request和Response的Header中传输配置信息和判断信息,达到数据的交互,从而减少流量的消耗。

HTTTP 缓存机制相关推荐

  1. Django缓存机制

    Django缓存机制三个粒度:1 全站缓存 settings.py 全局配置文件用中间件:MIDDLEWARE = [# 'django.middleware.cache.UpdateCacheMid ...

  2. MyBatis复习笔记6:MyBatis缓存机制

    MyBatis缓存机制 MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制.缓存可以极大的提升查询效率. MyBatis系统中默认定义了两级缓存. 一级缓存和二级缓存. 默认情 ...

  3. java设置缓存机制

    2019独角兽企业重金招聘Python工程师标准>>> java设置缓存机制 所谓缓存,就是将程序或系统经常要调用的对象存在内存中,一遍其使用时可以快速调用,不必再去创建新的重复的实 ...

  4. Mybait缓存机制

    MyBatis同大多数ORM框架一样,提供了一级缓存和二级缓存的支持. 一级缓存:其作用域为session范围内,当session执行flush或close方法后,一级缓存会被清空. 二级缓存:二级缓 ...

  5. LeetCode实战:LRU缓存机制

    背景 为什么你要加入一个技术团队? 如何加入 LSGO 软件技术团队? 我是如何组织"算法刻意练习活动"的? 为什么要求团队的学生们写技术Blog 题目英文 Design and ...

  6. 微服务架构下静态数据通用缓存机制

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源 |  my.oschina.net/u/3971241/bl ...

  7. 微服务架构下的静态数据通用缓存机制!

    什么是静态数据 为什么需要缓存 通用缓存机制 总结 后记 在分布式系统中,特别是最近很火的微服务架构下,有没有或者能不能总结出一个业务静态数据的通用缓存处理机制或方案,这篇文章将结合一些实际的研发经验 ...

  8. 深入浅出 MyBatis 的一级、二级缓存机制

    一.MyBatis 缓存 缓存就是内存中的数据,常常来自对数据库查询结果的保存.使用缓存,我们可以避免频繁与数据库进行交互,从而提高响应速度. MyBatis 也提供了对缓存的支持,分为一级缓存和二级 ...

  9. ecshop的缓存机制更改

    ecshop是一个不错的平台,其中有一些地方可以改进一下 总体上看,就是一个大sql,global变量传来传去的,所有的只要取数据的时候,执行一个sql语句就可以了,但是一些需要缓存的地方,它使用的是 ...

最新文章

  1. eAccelerator和ionCube安装不上的解决办法
  2. 让CentOS 5.5支持ext4
  3. c# C++接口封装 汽车模拟仿真
  4. 在centos下报错:-bash: apt-get: 未找到命令
  5. 太阳花浏览器_一道浏览器面试题,就能看出你的前端功底
  6. 32岁,程序员,年薪60W,果断辞职考进体制内,月薪5K
  7. Inception V3 的 tensorflow 实现
  8. taobao-pamirs-schedule-2.0源码分析——任务队列分配源码分析
  9. redis java 存储对象_安装redis 并把java对象存放在redis中
  10. 基础:正则表达式方便理解
  11. 使用Docker一键部署MongoDB
  12. 王 第潜艇三天 引用类型 继承
  13. 【水汐のc++】建立一个会员管理程序, 每个会员的登记内容包括会员编号、 会员卡号、累计消费金额,可以分别按会员编号、 会员卡号进行查询,也可以增加或删除会员信息。
  14. C语言给小学生出题(随机1~99进行四则运算)
  15. 每日一问-ChapGPT-20230416-中医基础-经络
  16. ZynqMP Vitis PS加载PL代码
  17. 江苏省计算机一级主要考什么,江苏省计算机一级考试复习资料 很全面的
  18. blur事件与click事件冲突的解决办法
  19. python去掉开头不想要的字符
  20. 超实用移动固态硬盘,Lexar雷克沙SL100 Pro

热门文章

  1. 将您重定向的次数过多什么意思_Linux重定向
  2. python理解浮点数运算的误差_Python 浮点数运算
  3. VLAN的划分和验证(简易版)
  4. 制作html5移动端页面,移动端H5页面制作规范
  5. 你也是业务开发?提前用这个设计模式预防产品加需求吧
  6. PHP-mysql的数据类型
  7. 外汇短线操作技巧攻略
  8. 浪潮之巅第五章 — 奔腾的芯(英特尔—Intel)
  9. Murmurhash 哈希算法 介绍与实现
  10. CentOS6.5修改主机名