ThinkPHP响应对象不会自动设置Last-Modified头,必须手动用gmdate()生成RFC 1123格式时间并设置;还需主动校验If-Modified-Since,匹配时立即发送304并exit,否则缓存失效。

ThinkPHP响应对象不自动设置Last-Modified
ThinkPHP的response()对象本身不会为你生成或注入Last-Modified头,它只负责发送你明确指定的响应头。你必须手动计算时间、格式化、设置头,并额外处理If-Modified-Since校验逻辑——否则浏览器收不到304,永远返回200。
必须用gmdate()生成GMT格式时间戳
Last-Modified值不是随便拼个时间字符串就行,必须严格符合RFC 1123标准(例如Tue, 01 Sep 2026 10:09:00 GMT)。用date()会带本地时区,浏览器可能忽略;必须用gmdate('D, d M Y H:i:s', $timestamp) . ' GMT'。常见错误是直接传time()却不转GMT,或漏掉末尾空格+GMT字面量。
校验If-Modified-Since要主动exit,不能只设header
即使你用response()->header('Last-Modified', $gmt)设置了响应头,若没检查$_SERVER['HTTP_IF_MODIFIED_SINCE']并提前终止流程,控制器后续逻辑仍会执行,最终返回200体内容。正确做法是:
- 读取
$_SERVER['HTTP_IF_MODIFIED_SINCE'],用strtotime()转为时间戳(它能安全处理浏览器发来的各种格式) - 与资源实际最后修改时间(如文件
filemtime()或数据库记录updated_at)比对:仅当资源更新时间 ≤ 请求头时间,才应返回304 - 确认后立即调用
header('HTTP/1.1 304 Not Modified')+exit,别依赖response()链式调用
ThinkPHP 6/8中response()->header()只是“准备发”
response()->header('Last-Modified', $val)只是把头加入待发送队列,它不拦截后续输出、不改变状态码、也不做任何条件判断。很多开发者误以为设了这个就万事大吉,结果发现缓存始终不生效——根本原因在于没写校验分支。动态内容(比如用户仪表盘)尤其要注意:修改时间得来自业务数据(如$user->update_time),不能硬写time()。
立即学习“PHP免费学习笔记(深入)”;



















