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

前言

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

http协议

http协议有一条规则:

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

源码

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

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

@Override
	public 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 phase
		if (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {
			logger.trace("Resource not modified");
			return;
		}
		
		// Apply cache settings, if any
		prepareResponse(response);

		// Check the media type for the resource
		MediaType mediaType = getMediaType(request, resource);

		// Content phase
		if (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

@Override
	public boolean checkNotModified(long lastModifiedTimestamp) {
		return checkNotModified(null, lastModifiedTimestamp);
	}
@Override
	public boolean checkNotModified(@Nullable String etag, long lastModifiedTimestamp) {
		......
		boolean validated = validateIfNoneMatch(etag);
		if (!validated) {
		    // 核心代码1
			validateIfModifiedSince(lastModifiedTimestamp);
		}

		// Update response
		if (response != null) {
			boolean isHttpGetOrHead = SAFE_METHODS.contains(getRequest().getMethod());
			if (this.notModified) {
				// 核心代码2
				response.setStatus(isHttpGetOrHead ?
						HttpStatus.NOT_MODIFIED.value() : HttpStatus.PRECONDITION_FAILED.value());
			}
			if (isHttpGetOrHead) {
				if (lastModifiedTimestamp > 0 && parseDateValue(response.getHeader(LAST_MODIFIED)) == -1) {
					// 核心代码3
					response.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协议的规范

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值