HTTP缓存带来的“bug”--HTTP 协议 Cache-Control

问题描述

先说背景。网站是用PHP开发的,未用任何框架,代码结构也很是简单。运行于阿里云服务器,并采用其CDN来作分发。根据业务需求,有的页面会判断用户浏览器类型,依此来选择PC或者手机端内容。php

在一次上线过程当中,遇到比较诡异的问题:用PC和手机分别访问页面时,网页内容未根据浏览器类型来区分。而在开发环境,页面却能正常显示。仔细排查了代码,没有发现问题出在什么地方。而线上环境也很差调试,只能靠猜了。
css

解决过程

开发环境一切正常,说明代码出问题的可能性不大(固然后面发现仍是代码的问题~)。而线上与开发环境的差异就在于多了一层CDN。会不会是CDN的问题?然而本人对CDN也是只知其一;不知其二的,只知道是它会缓存源网站内容,并就近对用户进行内容分发,来加速访问。若是用户请求的内容CDN并未缓存,就会发生回源。对图片、css、js等静态资源,CDN缓存是理所应当的。可是对html内容,由于通常都是PHP动态生成的,会有一些业务逻辑,缓存这些内容就不太合适了。因为相关判断浏览器类型的代码是通过验证的,因此问题应该不在网站自己。考虑到上面CDN相关内容,我就在怀疑是否是CDN把html都缓存下来了,致使用户请求压根没到网站服务器。因而打开浏览器console,查看请求响应头,并把问题页的响应头和正常页面进行对比,果真发现了问题。正常页面每次刷新后,响应头里的Date字段都会改变;而问题页的Date字段一直没变化!也就是说问题页取到的内容一直都是CDN缓存。再次对比发现,正常页面还有Cache-Control相关内容,而问题页没有。因而推测CDN会根据响应头来决定是否会缓存内容。在问题页代码中增长缓存控制相关header后,果真正常了。然而问题又来了,正常页面的Cache-Control是哪里输出的呢?代码中并无看到对应内容,估计是线上人为加了相关header,与开发环境代码不一致。html

总结

一直以来对http响应头中的缓存控制相关内容都没有注意,遇到问题才发现它们的重要性。本次解决这个问题,主要是增长了如下header:浏览器

header('Pragma: no-cache');//兼容老版本协议 http1.0可能不识别Cache-Control
header('Cache-Control: no-store, no-cache, must-revalidate');//告诉浏览器/代理 不缓存内容
header("Expires: Mon, 26 Jul 1970 05:00:00 GMT"); //把过时时间设置为以往的时间,基本等同于Cache-Control:no-cache

页面加上三行代码后基本可保证其内容不被缓存。缓存

阿里云CDN响应头中有几个关于缓存的字段须要注意:服务器

X-Cache,值包含HIT时,表示命中缓存;MISS则表示未命中,须要回源
X-Swift-SaveTime 缓存保存时间
X-Swift-CacheTime 缓存时长
Age 当前资源已缓存的时间,达到X-Swift-CacheTime时缓存过时,会回源

想了解更多HTTP协议相关内容,请查看HTTP协议简介框架

相关文章
相关标签/搜索