Tomcat中对静态资源的处理教程

2019-10-18 20:08:10王冬梅

检查是否过期,当前时间大于缓存条目设置的时间戳 如果过期,再检查资源内容是否修改 如果修改,清除这个缓存,读取最新内容

以上就是资源缓存简单的处理过程。

2. If 头域的处理

客户端接收并缓存请求的资源,,当再次请求此资源时,服务端根据特定的请求头域来验证资源是否修改,没有变动,则只返回一个 304 Not Modified 响应,否则返回资源的内容,从而节省带宽。

用于资源验证的头域有两种,分别是:Last-Modified+If-Modified-Since 和 ETag+If-None-Match。

Last-Modified+If-Modified-Since,单位是秒,这个容易理解,如果服务端资源的最后修改时间小于 If-Modified-Since 的值,表示资源无变动。与 If-Modified-Since 对应的有个 If-Unmodified-Since,它类似一个断言,小于此时间戳的资源才返回,大于等于的话会返回 412 Precondition Failed 的错误。

使用时间戳校验有几个弊端:

文件有可能只改变修改时间,内容不变 文件在秒以下的时间修改无法判断 服务器可能不能精确获取文件的最后修改时间。

因此,HTTP 引入了 ETag。ETag(Entity Tags) 资源唯一标识,可看做服务端为资源生成的一个 Token,用于校验资源是否修改。HTTP 只规定 ETag 要放在双引号内,没有规定内容是什么或者要怎么实现,Tomcat 生成 ETag 的逻辑是 "W/"" + contentLength + "-" + lastModified + """ ,其中 'W/' 表示大小写敏感。

ETag+If-None-Match,If-None-Match 的值由一个或多个 ETag 组成,多个以逗号分割,如果服务端资源的 ETag 与其中的任何一个都不匹配,表示请求的资源有修改;否则无变动。它还有一个特殊值-星号(*),只在资源上传时使用,通常是 PUT 方法,检查是否已经上传过。

此外 If-None-Match 的优先级高于 If-Modified-Since,也就是说,存在 If-None-Match 就不对最后修改时间进行校验。与 If-None-Match 相对的有个 If-Match,它也类似断言,只有资源的 ETag 匹配时才认为没有修改,通常用于断点续传。

Tomcat 实现此部分的核心代码如下:

// 返回 true 是才认为资源有变动
protected boolean checkIfHeaders(HttpServletRequest request,
  HttpServletResponse response,ResourceAttributes resourceAttributes)
  throws IOException {
 return checkIfMatch(request, response, resourceAttributes)
  && checkIfModifiedSince(request, response, resourceAttributes)
  && checkIfNoneMatch(request, response, resourceAttributes)
  && checkIfUnmodifiedSince(request, response, resourceAttributes);
}

2.1 一次请求流程

以请求 /main.css 静态资源为例,第一次请求响应头信息如下:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"72259-1557127244000"
Last-Modified: Mon, 06 May 2019 07:20:44 GMT
Content-Type: text/css
Content-Length: 72259
Date: Mon, 06 May 2019 07:20:57 GMT