HTTP请求头Cache-Control,设置 Flask 响应实现静态资源长时缓存的例子

HTTP缓存头的设置包括Cache-Control(用于本地缓存),Expires(用于本地缓存),Last-Modified(协商缓存),Etag(协商缓存)。

  • Cache-Control:指定请求和响应遵循的缓存机制。在请求消息或响应消息中设置Cache- Control并不会修改另一个消息处理过程中的缓 存处理过程。请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if- cached,响应消息中的指令包括public、private、no-cache、no-store、no-transform、must- revalidate、proxy-revalidate、max-age。

  • Expires:是一个绝对时间,作用相同于max-age,我理解的应该是这样nowTime+maxAge=expires;(http1.0)

  • Last-Modified:被访问的资源的最近一次更改时间(http1.0)

  • Etag:资源的一个唯一标志(http1.1)

RFC文档关于Cache的内容
Caching in HTTP

在资源请求响应中可以通过 Cache-Control 实现客户端缓存,减少重复资源下载。以我使用的 Python Flask 框架为例。Flask 中有专门的 static 静态路由终端,用于图像、JS、CSS 等静态资源的响应,那么特别地对该路由设置更高的缓存时间即 max-age 可以实现客户端长时间缓存或几乎永久缓存(更新则通过链接添加版本或摘要特征值等get参数)。

@app.after_request
def app_after_request(response):  
    if request.endpoint != 'static':
        return response
    response.cache_control.max_age = 15552000
    return response

以上代码中,对于 Flask 全局应用 app 的响应进行了过滤,如果请求端点为 static 静态资源专用路由,则设置 Headers 中 Cache-Control 的 max-age 为180天的秒数。

同样地,在 Flask 蓝本中,也有@蓝本名.after_request修饰器,给予修改请求响应头的机会。

Chrome下的问题

在 Chrome 浏览器中,一个显著的问题是刷新或者地址栏输入网址方式访问页面,所有请求都会自动设置 max-age=0

这个问题在 Superuser 网站上已有人提出来,how do i stop chrome sending cache control max age 0 when i hit enter

Chrome max-age=0

上面的回答也说明了,当使用后退按钮或者点击页面的链接形式打开窗口,Chrome 是不会自动添加 max-age=0的,只有当在地址栏输入地址,Chrome 总是会添加 max-age=0,这个就绕过了本地缓存。

协商缓存的例子

绕过缓存的例子 这次请求是浏览器普通刷新,相当于地址栏输入地址回车,结果是返回了304请求,资源还是从本地获取的,但是浪费了一次http 请求和响应。

直接使用本地缓存的例子

使用本地缓存的例子 本次请求是来自页面链接的点击,可以看到请求头内容非常的精简,没有 Cache-Control,响应状态码是200(from cache),重要的是该请求不是传递至服务端的,服务端不需要浪费性能去接收和响应一个本已缓存的资源请求。这一点对于一个大 PV 的网站来说非常重要。