本文将介绍ETag,以及Spring框架中如何使用ETag节约网络传输带宽。
1 定义
ETag是Entity Tag的缩写,可以认为是URL对象的身份标示。若两个URL对象的ETag值相同,则可认为这两个对象相同。
2 HTTP状态码
在从零搭建Web应用(一)中,我们有对HTTP做过简要的介绍。
HTTP请求示例
在HTTP响应报文中,会返回一个三位数字。这个数字被称之为HTTP状态码,英文全称是HTTP Status Code
,它用来表示HTTP响应报文的各种状态。在上图中红色方框圈出来的位置,便有多个返回403状态的HTTP响应报文,意思是该Url对象禁止被访问。
在网络请求中,最经常返回的应该是200状态。200表示OK,指请求正常处理并返回。不过用户印象最深刻的则非404莫属了。404指Not Found,意思是指定资源在服务器端未找到的意思。很多网站还会为404设置非常有意思的错误页面,比如:
404 Not Found
HTTP协议中定义了304的状态码。304表示Not Modified,指本次请求Url对象和上一次的对象相同,没有变化。
服务器在收到客户端的某个请求时,会确认该资源是否曾给过客户端。若给过,则确认在这期间资源是否有发生变化。若没有发生变化,则服务器可以返回304状态码给客户端,表示资源有效可继续使用。客户端在接收到304状态码后,可以直接使用原来请求过的资源。这样的好处有
-
对于客户端,该资源已经获取并完成了解析和渲染,所以不需要再次对该资源进行处理,节省了本地的计算资源;
-
对于服务器,该资源已经给过浏览器,因此服务器在返回HTTP响应时,可以只返回304状态码,不需要再传输具体内容。这便节约了传输带宽。
3 ETag和If-None-Match
服务器返回304状态的机制依赖于ETag
和If-None-Match
两个HTTP Header。当客户端请求某资源时,若在HTTP请求头中包含了If-None-Match
属性,则服务器会先获取到客户端所请求的资源,然后去计算ETag
值。如果ETag
值和If-None-Match
相同,则忽略已经得到的资源,直接返回客户端304状态。
4 Spring框架的处理
首先修改Spring Web MVC配置,启用ShallowEtagHeaderFilter
。ShallowETagHeaderFilter
是Spring框架中用于实现ETag特性的过滤器。Spring Web MVC的配置方法我们在Spring Web MVC配置方式汇总(四)中有过介绍。
public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
...
protected Filter[] getServletFilters() {
return new Filter[]{new ShallowEtagHeaderFilter()};
}
}
然后写一个Controller
类,用于处理http://localhost:8080/etag请求。
@RestController
public class MyController {
@RequestMapping("/etag")
public String greeting() {
return "We are trying to use etag feature.";
}
}
打开浏览器,在地址栏输入http://localhost:8080/etag访问服务器。此时我们可以使用浏览器的开发者工具观察HTTP报文信息。
首次请求
再次输入http://localhost:8080/etag,这时候客户端会将上一次服务器返回的ETag
值作为If-None-Match
发送给服务器。服务器发现这个值和新计算的ETag
值相同,则返回304状态码。
第二次请求
5 总结
-
ETag
和304状态码可以减少服务器和浏览器之间的信息传输量。有些用户习惯在浏览器端频繁刷新页面,这时304机制可以极大地降低网络传输带宽的损耗。 -
由于
ETag
需要服务器在每次收到If-None-Match
时,实时计算新的ETag
值和其比较。计算新的ETag
需要先获取资源,再计算。因此,即使开启了ETag
特性,服务器端的仍需要首先拿到资源,也就是说@RequestMapping方法仍会被执行。所以该机制优化的只是传输带宽,并没有降低服务器端计算资源的消耗。