HTTP缓存ShallowETag

1.直接使用

springboot项目在启动类main方法下配置

	@Bean
    public ShallowEtagHeaderFilter shallowETagHeaderFilter() {
        return new ShallowEtagHeaderFilter();
    }

web项目在web.xml配置过滤器

<filter>  
    <filter-name>shallowEtagHeaderFilter</filter-name>  
    <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</fliter-class>  
</filter>  
<filter-mapping>  
    <filter-name>shallowEtagHeaderFilter</filter-name>  
    <servlet-name>spring</servlet-name>  
</filter-mapping>

由于我使用了spring的security会导致HTTP缓存失效 所有需要配置下

//在Spring Security配置类中配置如下代码 如下图
http.headers().cacheControl().disable();

在重写处理HttpSecurity配置方法中添加
在这里插入图片描述

2.查看效果
2.1 我写了个直接返回数据的接口

在这里插入图片描述

2.2 在浏览器第一次查询

在这里插入图片描述

2.3 第二次请求

可以看到请求标头和响应标头的ETag一致 响应码也为304 数据来自缓存
在这里插入图片描述

2.4 更改数据 再次请求

我更改了book_author改成如下
在这里插入图片描述
我们再次请求查看,数据已经发生变更请求标头与响应标头ETag不一致
在这里插入图片描述

3.控制器添加对HTTP缓存

上面这种使用方法 所有符合生成ETag条件的请求都会做缓存如果我需要对指定的URL做缓存呢?
如下 spring官网上的案例
详情参阅Spring Http缓存

@GetMapping("/book/{id}")
public ResponseEntity<Book> showBook(@PathVariable Long id) {

    Book book = findBook(id);
    String version = book.getVersion();

    return ResponseEntity
            .ok()
            .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
            .eTag(version) // lastModified is also available
            .body(book);
}
4.原理解析

原理:Spring官方写的
在这里插入图片描述
翻译一下如下:

所述ShallowEtagHeaderFilter过滤器通过缓存写入响应的内容,并从它计算MD5哈希创建一个“浅”的ETag。客户端下次发送时,它会执行相同操作,但它也会将计算值与If-None-Match 请求标头进行比较,如果两者相等,则返回304(NOT_MODIFIED)

在这里插入图片描述

ShallowEtagHeaderFilter处理的核心源码

private void updateResponse(HttpServletRequest request, HttpServletResponse response) throws IOException {
		//返回指定类型的适当响应对象
		ContentCachingResponseWrapper responseWrapper =
				WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
		//判断当前对象是否为null 等于null返回一个信息为“ContentCachingResponseWrapper not found”的非法参数异常
		Assert.notNull(responseWrapper, "ContentCachingResponseWrapper not found");
		//获取响应内容
		HttpServletResponse rawResponse = (HttpServletResponse) responseWrapper.getResponse();
		//获取响应状态码
		int statusCode = responseWrapper.getStatusCode();
		//判断提交的请求是否编写了响应状态和响应标头
		if (rawResponse.isCommitted()) {
			//最终调用response.flushBuffer()方法 将缓冲区的数据复制到响应当中
			responseWrapper.copyBodyToResponse();
		}
		//判断给定的请求和响应是否符合生成ETag的条件 
		else if (isEligibleForEtag(request, responseWrapper, statusCode, responseWrapper.getContentInputStream())) {
			//根据最新数据生成ETag
			String responseETag = generateETagHeaderValue(responseWrapper.getContentInputStream(), this.writeWeakETag);
			//把ETag放入响应标头中
			rawResponse.setHeader(HEADER_ETAG, responseETag);
			//获取从请求request携带过来的ETag
			String requestETag = request.getHeader(HEADER_IF_NONE_MATCH);
			//判断两个ETag是否相等
			if (requestETag != null && ("*".equals(requestETag) || compareETagHeaderValue(requestETag, responseETag))) 
				//相等的话就返回一个304的响应码
				rawResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			}
			else {
				//不相等就更新响应中的数据
				responseWrapper.copyBodyToResponse();
			}
		}
		else {
			//上面两个条件都不符合,更新响应中的数据
			responseWrapper.copyBodyToResponse();
		}
	}
5.作用
5.1优点:
  1. 用户访问快
  2. 节约服务器带宽
当响应为304的时候 浏览器并不需要从服务器拿取数据,直接从本地缓存中拿取,所以节省了时间及服务器带宽

缺点:不能节省CPU,java应用程序需要做的请求还是一样的,并且也需要进行数据库连接,服务器压力并没有降低

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值