Http实战之缓存、重定向(2)

简介: Http实战之缓存、重定向(2)

缓存控制


关于缓存控制我们可以分为两部分讨论


1.服务端如何进行缓存控制

2.客户端如何进行缓存控制


服务端控制


服务端进行缓存控制主要依赖Cache-Control、及Expires请求头,其中Expires已经不推荐使用。其优先级如下所示:


  • 附加一个Cache-Control: no-store首部到响应中去;
  • 附加一个 Cache-Control: no-cache 首部到响应中去;
  • 附加一个 Cache-Control: must-revalidate 首部到响应中去;
  • 附加一个 Cache-Control: max-age 首部到响应中去;
  • 附加一个 Expires 日期首部到响应中去;


Cache-Control: no-store,客户端禁止使用缓存

Cache-Control: no-cache,客户端可以进行缓存,但每次使用缓存时必须跟服务器进行再验证

Cache-Control: must-revalidate ,客户端可以进行缓存,在缓存过期后必须进行再验证,跟no-cache的区别在于must-revalidate强调的是缓存过期后的行为,因为在某些情况下为了提升效率客户端会使用已经过期的缓存,如果服务端指定了Cache-Control: must-revalidate ,那么缓存过期后不能直接使用,必须进行再验证。no-cache不论缓存是否过期都需要客户端发起再验证。


Cache-Control: max-age ,指明了缓存的有效期,是一个相对时间,单位为秒

Expires ,指明了缓存的有效,是一个决定时间。HTTP 设计者后来认为,由于很多服务器的时钟都不同步,或者不正确,所以最好还是用剩余秒 数,而不是绝对时间来表示过期时间,已经不推荐使用。


客户端控制


上面我们介绍了,服务器端如何在响应头中添加响应的字段来浏览来是否可以使用缓存,同样,客户端自己也可以控制,以浏览器为例,这里我们主要说三个场景:


1.浏览器刷新

即我们按F5刷新页面的时候,该页面的http请求中会添加:Cache-Control:max-age:0, 即说明缓存直接失效啦,就不走缓存了,直接从服务器端读取数据。


2.浏览器强制刷新

即我们按ctrl+f5强制刷新页面的时候,该页面的http请求会添加:Cache-Control:no-cache; 即表示此时要首先去服务器端验证资源是否有更新,如果有更新则直接返回最新资源,如果没有更新,则返回304,然后浏览器端判断是304的话,则从缓存中读取数据。


3.浏览器前进后退重定向

当我们点击浏览器的前进后退操作时,这个时候请求中不会有Cache-Control的字段,没有该字段,就表示会检查缓存,直接利用之前的资源,不再重新请求服务器。


httpClient缓存代码分析


需要引入HttpClinet缓存模块

微信图片_20221114125339.png

测试代码如下:

public class CacheHttpClient {
  static CacheConfig cacheConfig =
    CacheConfig.custom().setMaxCacheEntries(1000).setMaxObjectSize(8192).build();
  static CloseableHttpClient cachingClient =
    CachingHttpClients.custom().setCacheConfig(cacheConfig).build();
  public static void main(String[] args) throws Exception {
    Scanner scanner = new Scanner(System.in);
    while (true) {
      scanner.nextLine();
      HttpCacheContext context = HttpCacheContext.create();
      HttpGet httpget = new HttpGet("http://www.mydomain.com/content/");
      CloseableHttpResponse response = cachingClient.execute(httpget, context);
      try {
        CacheResponseStatus responseStatus = context.getCacheResponseStatus();
        switch (responseStatus) {
          case CACHE_HIT:
            System.out.println(
              "A response was generated from the cache with "
              + "no requests sent upstream");
            break;
          case CACHE_MODULE_RESPONSE:
            System.out.println(
              "The response was generated directly by the " + "caching module");
            break;
          case CACHE_MISS:
            System.out.println("The response came from an upstream server");
            break;
          case VALIDATED:
            System.out.println(
              "The response was generated from the cache "
              + "after validating the entry with the origin server");
            break;
          default:
            // do nothing
        }
      } finally {
        response.close();
      }
    }
  }
}

缓存的核心处理逻辑位于org.apache.http.impl.client.cache.CachingExec#execute中,如下:

微信图片_20221114125544.png

缓存处理的核心代码我在图中已经做了标注

1.是否启用缓存,代码很简单

image.png

2.从缓存中获取信息,这里的key实际就是访问时使用的URI,缓存底层默认使用的是一个Map

微信图片_20221114125635.png

3.缓存未命中时会向服务器发送真正的请求,代码简单,不做分析

4.缓存命中,这时要处理两种情况:「缓存未过期」、「缓存过期+再验证」

微信图片_20221114125708.png

对http协议了解后,这块的代码非常简单,所以笔者在这里也不赘述了


重定向


https://datatracker.ietf.org/doc/html/rfc2616#page-61

接下来我们聊聊重定向,跟重定向相关的响应码如下:

状态码

原因短语

含 义

301

Moved Permanently

在请求的 URL 已被移除时使用。响应的 Location 首部中应该包含 资源现在所处的URL,【301代表永久重定向】,客户端在后续访问时应该将URL替换为本次Location首部标明的URL

302

Found

【302代表临时重定向】,客户端后续访问时不需要进行替换,仍然应该使用原来的URL

303

See Other

其主要目的是允许 POST 请求的响应将客户端定向到某个资源上去

307

Temporary Redirect

也是临时重定向,跟302类似

你可能已经注意到 302、303 和 307 状态码之间存在一些交叉。这些状态码的用法有着细微的差别,大部分差别都源于 【HTTP/1.0 和 HTTP/1.1 应用程序对 这些状态码处理方式的不同】。


当 HTTP/1.0 客户端发起一个 POST 请求,并在响应中收到 302 重定向状态码时, 它会接受 Location 首部的重定向 URL,并向那个 URL 发起一个 GET 请求(而不 会像原始请求中那样发起 POST 请求)。


HTTP/1.0 服务器希望 HTTP/1.0 客户端这么做——如果 HTTP/1.0 服务器收到来自 HTTP/1.0 客户端的 POST 请求之后发送了 302 状态码,服务器就期望客户端能够接 受重定向 URL,并向重定向的 URL 发送一个 GET 请求。


问题出在 HTTP/1.1。HTTP/1.1 规范使用 303 状态码来实现同样的行为(服务器发 送 303 状态码来重定向客户端的 POST 请求,在它后面跟上一个 GET 请求)。


为了避开这个问题,HTTP/1.1 规范指出,对于 HTTP/1.1 客户端,用 307 状态码取 代 302 状态码来进行临时重定向。这样服务器就可以将 302 状态码保留起来,为 HTTP/1.0 客户端使用了。


HttpClient重定向代码分析


核心代码位于:org.apache.http.impl.execchain.RedirectExec#execute

image.png

重定向的处理策略都定义在redirectStrategy中,我们看下它的代码:

1.isRedirected方法,是否需要重定向

微信图片_20221114130138.png

实际就是判断状态码是不是我们前文提到过的301、302、303、307。

2.getRedirect方法,重定向时需要封装的请求信息:请求方法+URL

微信图片_20221114130209.png


写在最后


本来打算这篇文章作为《HTTP实战》的最后一篇的,实在太忙再加上篇幅原因,关于数据压缩、分块传输、范围请求就放到下篇文章吧~


参考:


《Http权威指南》


https://hc.apache.org/httpcomponents-client-4.5.x/current/tutorial/html/caching.html

https://datatracker.ietf.org/doc/html/rfc2616#page-74

https://datatracker.ietf.org/doc/html/rfc7232#page-13

https://www.digitalocean.com/community/tutorials/web-caching-basics-terminology-http-headers-and-caching-strategies

相关文章
|
3月前
|
存储 缓存 安全
第二章 HTTP请求方法、状态码详解与缓存机制解析
第二章 HTTP请求方法、状态码详解与缓存机制解析
|
15天前
|
缓存 JSON 前端开发
超详细讲解:http强缓存和协商缓存
超详细讲解:http强缓存和协商缓存
|
2月前
|
网络协议
windows_server2012搭建iis并配置http重定向 iis转发
windows_server2012搭建iis并配置http重定向 iis转发
116 1
|
20天前
|
数据采集 JSON API
HTTP协议实战演练场:Python requests库助你成为网络数据抓取大师
【7月更文挑战第30天】在网络数据抓取中,Python的`requests`库凭借其简洁的API和强大功能脱颖而出。首先确保已通过`pip install requests`安装库。实战演练包括:发送GET请求获取数据(如`requests.get(url)`),处理JSON响应(利用`.json()`方法解析),添加请求头以绕过反爬虫机制(如设置`User-Agent`),以及发送POST请求提交数据。掌握这些技能的同时,务必遵守法律法规和网站政策。
41 6
|
20天前
|
数据采集 网络协议 API
|
2月前
|
缓存 负载均衡 NoSQL
Redis系列学习文章分享---第十四篇(Redis多级缓存--封装Http请求+向tomcat发送http请求+根据商品id对tomcat集群负载均衡)
Redis系列学习文章分享---第十四篇(Redis多级缓存--封装Http请求+向tomcat发送http请求+根据商品id对tomcat集群负载均衡)
48 1
|
2月前
|
域名解析 存储 缓存
HTTP请求流程概览:浏览器构建请求行含方法、URL和版本;检查缓存;解析IP与端口
【6月更文挑战第23天】 HTTP请求流程概览:浏览器构建请求行含方法、URL和版本;检查缓存;解析IP与端口;TCP连接(HTTP/1.1可能需排队);三次握手;发送请求头与体;服务器处理并返回响应;TCP连接可能关闭或保持;浏览器接收并显示响应,更新缓存。HTTP版本间有差异。
47 5
|
1月前
|
缓存 JSON 算法
http【详解】状态码,方法,接口设计 —— RestfuI API,头部 —— headers,缓存
http【详解】状态码,方法,接口设计 —— RestfuI API,头部 —— headers,缓存
34 0
|
3月前
|
存储 缓存 前端开发
http缓存机制
HTTP缓存机制通过缓存控制头、实体标签和最后修改时间头优化Web性能,减少网络请求。Cache-Control指令如`public`, `private`, `max-age`, `no-cache`, `no-store`管理缓存行为。ETag用于验证资源完整性,Last-Modified检查资源是否更新。前端可利用Web存储和服务工作者进行细粒度缓存控制。正确配置缓存关键在于适应应用场景和需求。