SpringBoot处理静态文件缓存机制详解

article/2025/9/3 11:17:20

前言

紧接上文SpringBoot处理静态文件源码分析,分析下其中处理静态文件时的缓存机制

http协议

http协议有一条规则:

  1. 当response header中携带Last-Modified时,当再次发起一个相同请求时会把Last-Modified的值放到request header的If-Modified-Since字段中
  2. 当服务端返回http状态码为304时就会从当前缓存中获取资源

源码

基于上述协议我们来看SpringBoot中的源码

直接看ResourceHttpRequestHandler的handleRequest,ResourceHttpRequestHandler是处理静态文件的处理器,不了解的可以从上一篇文章开始看

@Overridepublic void handleRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// For very general mappings (e.g. "/") we need to check 404 first// 获取资源文件Resource resource = getResource(request);// 核心代码// Header phaseif (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {logger.trace("Resource not modified");return;}// Apply cache settings, if anyprepareResponse(response);// Check the media type for the resourceMediaType mediaType = getMediaType(request, resource);// Content phaseif (METHOD_HEAD.equals(request.getMethod())) {setHeaders(response, resource, mediaType);return;}ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);if (request.getHeader(HttpHeaders.RANGE) == null) {Assert.state(this.resourceHttpMessageConverter != null, "Not initialized");setHeaders(response, resource, mediaType);this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);}......}

上述的核心方法就是checkNotModified

@Overridepublic boolean checkNotModified(long lastModifiedTimestamp) {return checkNotModified(null, lastModifiedTimestamp);}
@Overridepublic boolean checkNotModified(@Nullable String etag, long lastModifiedTimestamp) {......boolean validated = validateIfNoneMatch(etag);if (!validated) {// 核心代码1validateIfModifiedSince(lastModifiedTimestamp);}// Update responseif (response != null) {boolean isHttpGetOrHead = SAFE_METHODS.contains(getRequest().getMethod());if (this.notModified) {// 核心代码2response.setStatus(isHttpGetOrHead ?HttpStatus.NOT_MODIFIED.value() : HttpStatus.PRECONDITION_FAILED.value());}if (isHttpGetOrHead) {if (lastModifiedTimestamp > 0 && parseDateValue(response.getHeader(LAST_MODIFIED)) == -1) {// 核心代码3response.setDateHeader(LAST_MODIFIED, lastModifiedTimestamp);}if (StringUtils.hasLength(etag) && response.getHeader(ETAG) == null) {response.setHeader(ETAG, padEtagIfNecessary(etag));}}}return this.notModified;}

核心代码1,validateIfModifiedSince方法,lastModifiedTimestamp的值是当前资源文件的最后修改时间

private boolean validateIfModifiedSince(long lastModifiedTimestamp) {if (lastModifiedTimestamp < 0) {return false;}// IF_MODIFIED_SINCE = "If-Modified-Since"long ifModifiedSince = parseDateHeader(IF_MODIFIED_SINCE);if (ifModifiedSince == -1) {return false;}// We will perform this validation...this.notModified = ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000);return true;}

简单的说就是获取request中的If-Modified-Since,如果这个值不为空并且大于等于资源文件的最近修改时间,那么就相当于文件没有被修改。当满足条件时修改notModified 的值为true

核心代码2处,当notModified 为true时修改http的状态码为HttpStatus.NOT_MODIFIED.value(),值为304

核心代码3处,response.setDateHeader(LAST_MODIFIED, lastModifiedTimestamp);

LAST_MODIFIED = “Last-Modified”

在response的header上设置Last-Modified值,当浏览器接收到该参数后,再次发起请求就会在request中传递If-Modified-Since值了

到这里就源码就分析完了

实践

自己实践下,写个方法

@ApiOperation("cache")@RequestMapping("/cache")public String cache(HttpServletRequest request, HttpServletResponse httpServletResponse) {httpServletResponse.addDateHeader("Last-Modified",System.currentTimeMillis());String since = request.getHeader("If-Modified-Since");if (StringUtils.isNotEmpty(since)) {httpServletResponse.setStatus(304);return "当前走了缓存,所以我不会返回";}return "返回" + System.currentTimeMillis();}

浏览器多次访问,第一次返回http状态码是200,并且response携带了Last-Modified字段
在这里插入图片描述
接下去访问结果

在这里插入图片描述
可以看到用到了缓存,因为值没有发生改变,并且request的header中携带了If-Modified-Since参数

总结

SpringBoot中处理静态资源的处理器使用了验证文件是否修改的缓存机制,其机制的实现依赖于http协议的规范


http://chatgpt.dhexx.cn/article/VVsR23kn.shtml

相关文章

apache设置html缓存,宝塔面板apache配置静态文件缓存

将网站静态资源内容,如jpg,gif,png,js,css文件,页面打开时自动缓存到本地,而不是每次都去从服务器请求资源,设置一定的缓存时间,这样做可以减轻服务器的带宽压力,同时使网页打开速度加快,提高用户体检。 宝塔面板如何配置静态文件缓存呢?下面我们一起来操作 加载mod_ex…

linux vi 缓存文件,Vim中的几种文件备份方法总结

一、Vim 的交换文件 .filename.swp 默认交换文件在打开文件的时候就会产生交换文件&#xff0c;正常退出的时候才会删除交换文件(断电&#xff0c;CtrlZ强制退出就不会删除)&#xff0c;内容大致是这个样子。 通过在 Vim 配置文件设置 set noswapfile 来关闭交换文件。 二、 Vi…

CMake中set/unset的使用

CMake中的set命令用于将普通、缓存或环境变量(normal, cache, or environment variable)设置为给定值&#xff0c;其格式如下&#xff1a;指定<value>...占位符(placeholder)的此命令的签名需要零个或多个参数。多个参数将作为分号分割的list连接&#xff0c;以形成要设置…

Nginx缓存静态文件

nginx的一大功能就是完成静态资源的分离部署&#xff0c;减轻后端服务器的压力&#xff0c;如果给这些静态资源再加一级nginx的缓存&#xff0c;可以进一步提升访问效率。 第一步&#xff1a;添加nginx.conf的http级别的缓存配置 ##cache##proxy_connect_timeout 500;#跟后端服…

第一个c语言简单小程序

还有很多不会的地方&#xff0c;以后还要好好学习才行

C语言小程序实现电脑关机

一、需求分析 1.电脑在2分钟后关机&#xff1b; 2.输入 我最棒 则取消电脑关机 3.输入错误时&#xff0c;可以在2分钟内重复输入 二、代码 #include<stdio.h> #include<stdlib.h> #include<string.h> int main() {char arr[10] {0};system("shutd…

【C/C++ 经典小程序(一)】

【1】九九乘法表 输出9*9口诀。共9行9列&#xff0c;i控制行&#xff0c;j控制列。 #include <stdio.h> void main() {int i,j,result;for (i1;i<10;i){ for(j1;j<i;j){resulti*j;printf("%d*%d%-3d",i,j,result);/*-3d表示左对齐&#xff0c;占3位*/}pr…

c语言编写简单实用的小程序,C语言编写一个小程序

用C/C编写一个小程序 #include using namespace std; int main() { int b[6]{1,2,2,3,4,5},i,j,k,l,m,n,p,c,d,*a[6]; for(j0;j<6;j) a[j]&b[j]; for(j0;j<6;j) { a[0]&b[j]; for(k0;k<6;k) { if(kj) continue; a[1]&b[k]; for(l0;l<6;l) { if(lj||lk)…

编写C语言的最简单小程序Hello world和函数使用

编写C语言的最简单小程序Hello world 一、示例一 1、编写demo.c程序 #include<stdio.h> int main() {printf("Hello world!");return 0; } 程序的第一行 #include <stdio.h> 是预处理器指令&#xff0c;告诉 C 编译器在实际编译之前要包含 stdio.h 文…

C语言小程序:通讯录(文件版)

在静态版本的通讯录里面实现了通讯录的基本逻辑&#xff0c;但是空间大小是固定的&#xff0c;这样子就会显得很不灵活&#xff0c;会有浪费空间和空间不足的问题&#xff0c;所以在动态版本的通讯里面我们通过动态内存开辟使用malloc函数给通讯录动态的开辟一块空间&#xff0…

C语言有趣的小程序

最近闲着没事写了一个C语言小程序,就当作是玩玩。 本小程序的各个功能都是通过dos命令来实现的。 运行结果如下图: 该小程序有以下几个功能: 1、启动计算器 2、新建记事本 3、打开画图板 4、定时关机(15s、30s、60s) 5、显示系统时间或修改 6、重启计算机 小程序源代码…

C语言小程序:通讯录(静态版)

哈喽各位老铁们&#xff0c;今天给大家带来一期通讯录的静态版本的实现&#xff0c;何为静态版本后面会做解释&#xff0c;话不多说&#xff0c;直接开始&#xff01; 关于通讯录&#xff0c;其实也就是类似于我们手机上的通讯录一样&#xff0c;有着各种各样的功能&#xff0c…

C语言小程序分享

本文为大一时所写的文章&#xff08;2017/4/23&#xff09;&#xff0c;文笔还很生疏&#xff0c;在很多问题上认识不深&#xff0c;算是在学校的微信公众号上的一个编程探究模块上的投稿&#xff0c;本人当时也参与了本模块的维护和管理。补档。 上个周末的一个下午&#xff0…

C语言小程序-学生成绩统计系统

C语言小程序-学生成绩统计系统 参考了 另一位博主的代码(https://blog.csdn.net/qq_36503589/article/details/53106983) 我后来写的成绩排序版本链接&#xff1a;https://blog.csdn.net/qq_43617268/article/details/103491760 功能介绍&#xff1a;本程序可以输入50人以内的…

C语言10个经典小程序——小白必备!

网上有很多的人说编程有多么多么无聊。。。。So Boring ! 。。。其实小编想说:不要管别人怎么说,别人说什么,做你自己喜欢做的事就好。坚持下来,你会发现编程的乐趣的。。。。当然,如果你觉得学习编程语言很痛苦,坚持了一段时间后无果,南无果断放弃未必不是一个好的选择…

C语言小程序:如何用代码“画”出一个爱心

利用ASCII编码第三个字符&#xff0c;作为基础&#xff0c;然后利用三个多重循环画出一个爱心出来。要使用控制台改变运行框大小和文字的颜色&#xff0c;黑白的爱心不免有些诡异。 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <math.h> #inclu…

我的第一个c语言小程序

标题&#xff1a;判断题答题小程序 Author: plc6666 软工专业 工科男 格言&#xff1a;总有人间一两风&#xff0c;填我十万八千梦。 文章目录 标题&#xff1a;判断题答题小程序 一.程序的由来二.程序的状况1.程序实现了颜色转换的功能2.程序能随机抽20题&#xff0c;不重复3.…

C语言10个经典小程序

【程序1】 题目&#xff1a;有1、2、3、4个数字&#xff0c;能组成多少个互不相同且无重复数字的三位数&#xff1f;都是多少&#xff1f; 1.程序分析&#xff1a;可填在百位、十位、个位的数字都是1、2、3、4。组成所有的排列后再去       掉不满足条件的排列。 2.程序源…

用 C语言的写出几个小程序

系列文章目录 前言 1、第一章&#xff1a;求出一个整型数组中的最大值 2、第二章&#xff1a;打印出100~999之间所有的水仙花数 3、第三章&#xff1a;输入一个数&#xff0c;打印出n行杨辉三角 4、第四章&#xff1a;小只因跳楼梯问题 5、第五章&#xff1a;创建一个含是…

C语言小程序

1、猜数字游戏 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <time.h>//猜数字游戏 int main() {int guess 0;//生成随机数//0~99 --> 1~100int ret rand() % 100 1;//生成随机数的函数printf("请猜数字 …