IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 拦截器CacheInterceptor -> 正文阅读

[网络协议]拦截器CacheInterceptor

CacheInterceptor拦截器

在说第三个拦截器缓存拦截器之前,我们先了解下http协议的缓存机制是怎么样的

缓存规则分为强制缓存和对比缓存两种。

http把对于缓存的控制规则都放在头部的几个字段里了。

Cache-Control

Cache-Control常见的取值有private、public、no-cache、max-age,no-store,默认为private

private: 客户端可以缓存
public: 客户端和代理服务器都可缓存
max-age: 内容将在 xxx 秒后失效,单位秒
no-cache: 使用对比缓存来验证缓存数据,会发送请求和服务器对比,看是否使用本地缓存的
no-store: 所有内容都不会缓存,强制缓存,对比缓存都不会触发

强制缓存

假如配置了max-age的值为3600,那么当前请求就会默认缓存1个小时,在一个小时内,去请求这条数据,都会使用本地的缓存数据作为响应。

假如no-store,则每次请求都会去服务器请求最新的数据

对比缓存

如果使用对比缓存,那么服务器会去对比客户端发送过来的数据和服务器上的资源是不是一样的,如果一样,则服务器只会响应一个302状态,并不会把客户端请求的资源响应回去,当客户端接收到响应,解析为302,则会去缓存中获取数据。否则解析获取最新响应数据。

对比缓存又有2组规则:ETag/If-None-MatchLast-Modified/If-Modified-Since

ETag/If-None-Match

当第一次请求资源时,服务器会在响应头里加上ETag标识,如W/“4342c344-8d3”,该标识的生成规则由服务器决定,一般是 文件的hash值。

当再次请求资源时,客户端的头会附带If-None-Match,值为W/“4342c344-8d3”,服务器接收到请求后,如果和服务器上的资源运算出的ETag相同,那它就会返回302,否则就会返回200并附带资源文件到响应里。

Last-Modified/If-Modified-Since

当第一次请求资源时,服务器响应头里会有资源的最后修改时间Last-Modified:Fri, 21 Jan 2022 02:54:57 GMT。

下一次请求,客户端就会在请求头上增加头If-Modified-Since:Fri, 21 Jan 2022 02:54:57 GMT。服务器收到请求后,如果这个时间比服务器该资源最后的修改时间早的话,说明被改动过,返回最新资源,否则服务器返回302,客户端则取缓存资源。

注意上面的两组规则,ETag/If-None-Match 优先级大于 Last-Modified/If-Modified-Since

知道以上缓存规则后,我们再来解读CacheInterceptor这个拦截器的代码:

public Response intercept(Chain chain) throws IOException {
    //获取当前请求的缓存响应
    Response cacheCandidate = cache != null
        ? cache.get(chain.request())
        : null;

    long now = System.currentTimeMillis();
	
    /**
    * 这里面会根据请求头中的缓存配置是否使用缓存(比方是否有If-None-Match、If-Modified-Since、maxAge),
    * 来赋值strategy的响应cacheResponse是否为空,为空则不使用缓存
    */
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    Request networkRequest = strategy.networkRequest;
    Response cacheResponse = strategy.cacheResponse;

    //统计缓存使用次数
    if (cache != null) {
        cache.trackResponse(strategy);
    }

    //如果缓存响应为空,则直接关闭缓存对象
    if (cacheCandidate != null && cacheResponse == null) {
        closeQuietly(cacheCandidate.body()); 
    }

    //当CacheStrategy里的onlyIfCached这个值配置为false时,networkRequest会为空,这个值表示不使用网络
    //不使用网络,并且缓存响应也为空时,就报错504
    if (networkRequest == null && cacheResponse == null) {
        return new Response.Builder()
            .request(chain.request())
            .protocol(Protocol.HTTP_1_1)
            .code(504)
            .message("Unsatisfiable Request (only-if-cached)")
            .body(Util.EMPTY_RESPONSE)
            .sentRequestAtMillis(-1L)
            .receivedResponseAtMillis(System.currentTimeMillis())
            .build();
    }

    //不使用网络,但是有缓存响应,则返回缓存响应
    if (networkRequest == null) {
        return cacheResponse.newBuilder()
            .cacheResponse(stripBody(cacheResponse))
            .build();
    }

    Response networkResponse = null;
    try {
        //向下调用拦截器,请求网络
        networkResponse = chain.proceed(networkRequest);
    } finally {
        // If we're crashing on I/O or otherwise, don't leak the cache body.
        if (networkResponse == null && cacheCandidate != null) {
            closeQuietly(cacheCandidate.body());
        }
    }

    // If we have a cache response too, then we're doing a conditional get.
    if (cacheResponse != null) {
        if (networkResponse.code() == HTTP_NOT_MODIFIED) {
            //当缓存不为空,且服务器返回304时,则说明缓存内容没有变,使用缓存响应
            Response response = cacheResponse.newBuilder()
                .headers(combine(cacheResponse.headers(), networkResponse.headers()))
                .sentRequestAtMillis(networkResponse.sentRequestAtMillis())
                .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
                .cacheResponse(stripBody(cacheResponse))
                .networkResponse(stripBody(networkResponse))
                .build();
            networkResponse.body().close();

            // Update the cache after combining headers but before stripping the
            // Content-Encoding header (as performed by initContentStream()).
            cache.trackConditionalCacheHit();
            //更新缓存
            cache.update(cacheResponse, response);
            //返回缓存响应
            return response;
        } else {
            //服务器返回非304,则缓存不可用,关闭缓存
            closeQuietly(cacheResponse.body());
        }
    }

    Response response = networkResponse.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();

    if (cache != null) {
        //如果规则配置使用缓存,则更新最新的响应到缓存里
        if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
            CacheRequest cacheRequest = cache.put(response);
            //返回通过网络最新响应重新构造出来的响应给上层
            return cacheWritingResponse(cacheRequest, response);
        }
		//规则配置了不使用缓存,则删除缓存
        if (HttpMethod.invalidatesCache(networkRequest.method())) {
            try {
                cache.remove(networkRequest);
            } catch (IOException ignored) {
                // The cache cannot be written.
            }
        }
    }

    return response;
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-02-09 21:05:20  更:2022-02-09 21:06:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:55:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码