tomcat缓存静态资源深入

之前看过apach及nginx对于静态资源(含js,图片,css等)部分的缓存,用于加速并减轻后台实际web服务器的压力。

静态资源缓存是WEB服务器优化的一种手段,基本原理如下:

1.客户端浏览器请求服务器一个服务(该服务含有图片,js等静态资源),通常会对于每一个网页中的独立图片或js文件发送一个http请求

2.WEB服务器对于每个资源HTTP请求进行解析,并生成一个资源修改时间的唯一值(可以是etag或last_modified参数),放入服务器端map,key为资源url,value为资源修改时间。最后将此资源修改时间的唯一值包含在http头上返回,因为是首次请求,所以会将所有内容放在http body中一并返回给客户浏览器端

3.客户浏览器接收服服务器响应,并将服务器返回的资源修改时间作为key放入浏览器客户端,value为http body中的实际资源内容

4.客户浏览器再次请求静态资源时,会将资源修改时间一并发送给服务器

5.服务端会从最新的map中取出该资源url对应的修改时间,如果值晚于客户端请求的资源修改时间,这时会返回最新的已经修改过的资源给客户端。否则返回304 not modifed

这里记录资源修改时间的方式有etag及last_modified。最先有的是last_modified,它的工作方式就是上述介绍的,但缺点是只能精确到秒级别。也就是说当你在一秒中修改资源两次,而客户端拿到的是第一次修改,那之后就算客户端第二次再次请求也不会拿到最新的资源。

而etag的出现正是为了解决last_modified的秒级问题,于http 1.1被提出。

今天测试了下,在没有nginx等前端反向代理服务器时,tomcat竟然默认对静态资源做了缓存。

tomcat默认运用etag及last_modifed。etag与if_no_match(客户端浏览器上传时在http head中应该放的属性名)一起使用,last_modified与If-Modified-Since一起使用。

客户端首次请求时,得到请求响应数据如下:

GET http://localhost:8080/webTest/jsp/index.jsp [HTTP/1.1 200 OK 1ms]

GET http://localhost:8080/webTest/js/hello.js [HTTP/1.1 200 OK 1ms]

GET http://localhost:8080/webTest/img/a.jpg [HTTP/1.1 200 OK 2ms]

我们看一下Hello.js这个请求响应具体信息:

server Apache-Coyote/1.1 (表明服务器是tomcat)

Last-Modified:    Sun, 11 May 2014 10:54:33 GMT

Etag:    W/"175-1399805673000"

Date:    Sun, 11 May 2014 10:59:23 GMT

Content-Type:    application/javascript;charset=UTF-8

Content-Length:    175

Accept-Ranges:    bytes

从上面可以看到tomcat即返回了last_modified也返回了etag。

客户端再次请求时,请求数据如下:

If-None-Match:    W/"175-1399805673000"

If-Modified-Since:    Sun, 11 May 2014 10:54:33 GMT

响应如下:

GET http://localhost:8080/webTest/jsp/index.jsp [HTTP/1.1 200 OK 1ms]

GET http://localhost:8080/webTest/js/hello.js [HTTP/1.1 304 Not Modified 1ms]

GET http://localhost:8080/webTest/img/a.jpg [HTTP/1.1 304 Not Modified 1ms]

从中我们可以看到tomcat对于静态数据作了缓存。

接着我们分析tomcat对于这部分静态缓存的判断处理,这部分逻辑是写在DefaultServlet类中,

我们可以在doGet方法中进入ServiceContext方法中找到以下源码:

// Check if the conditions specified in the optional If headers are

// satisfied.

if (cacheEntry.context == null) {

// Checking If headers

boolean included =

(request.getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR) != null);

if (!included

&& !checkIfHeaders(request, response, cacheEntry.attributes)) {  //这句判断是否需要返回整个资源请求

return;

}

}

上面源码的  if (!included

&& !checkIfHeaders(request, response, cacheEntry.attributes))

用于判断是否需要返回整个资源,如果indcluded与checkIfHeaders方法返回的都是false,这时就直接返回,说明资源未修改,或者是缓存不支持的请求方式。

我们接着查看checkIfHeaders方法:

/**

* Check if the conditions specified in the optional If headers are

* satisfied.

*

* @param request The servlet request we are processing

* @param response The servlet response we are creating

* @param resourceAttributes The resource information

* @return boolean true if the resource meets all the specified conditions,

* and false if any of the conditions is not satisfied, in which case

* request processing is stopped

*/

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);

}

可以看到tomcat只有当这四个属性全部返回true(也就是说全部认为资源已经改变)才会返回true,这样最终会将整个资源(最新修改过的)返回客户端。

在这里,我们从上面实际过程当中看到,浏览器第二次请求资源时在http请求header中放了

If-None-Match:    W/"175-1399805673000"

If-Modified-Since:    Sun, 11 May 2014 10:54:33 GMT

这两个属性。

因此我们查看

&& checkIfModifiedSince(request, response, resourceAttributes)

&& checkIfNoneMatch(request, response, resourceAttributes)

这两个方法

checkIfModifiedSince源码如下:

/**

* Check if the if-modified-since condition is satisfied.

*

* @param request The servlet request we are processing

* @param response The servlet response we are creating

* @param resourceInfo File object

* @return boolean true if the resource meets the specified condition,

* and false if the condition is not satisfied, in which case request

* processing is stopped

*/

protected boolean checkIfModifiedSince(HttpServletRequest request,

HttpServletResponse response,

ResourceAttributes resourceAttributes) {

try {

long headerValue = request.getDateHeader("If-Modified-Since");

long lastModified = resourceAttributes.getLastModified();

if (headerValue != -1) {

// If an If-None-Match header has been specified, if modified since

// is ignored.

if ((request.getHeader("If-None-Match") == null)

&& (lastModified < headerValue + 1000)) {

// The entity has not been modified since the date

// specified by the client. This is not an error case.

response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

response.setHeader("ETag", resourceAttributes.getETag());

return false;

}

}

} catch (IllegalArgumentException illegalArgument) {

return true;

}

return true;

}

源码中可以看到:

if ((request.getHeader("If-None-Match") == null)

&& (lastModified < headerValue + 1000)) {

这句话表明只有在客户端浏览器发送的请求头中不包含If-None-Match,IfModifiedSince才会生效。

我们接着看checkIfNoneMatch,源码如下:

/**

* Check if the if-none-match condition is satisfied.

*

* @param request The servlet request we are processing

* @param response The servlet response we are creating

* @param resourceInfo File object

* @return boolean true if the resource meets the specified condition,

* and false if the condition is not satisfied, in which case request

* processing is stopped

*/

protected boolean checkIfNoneMatch(HttpServletRequest request,

HttpServletResponse response,

ResourceAttributes resourceAttributes)

throws IOException {

String eTag = resourceAttributes.getETag();

String headerValue = request.getHeader("If-None-Match");

if (headerValue != null) {

boolean conditionSatisfied = false;

if (!headerValue.equals("*")) {

StringTokenizer commaTokenizer =

new StringTokenizer(headerValue, ",");

while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {

String currentToken = commaTokenizer.nextToken();

if (currentToken.trim().equals(eTag))

conditionSatisfied = true;

}

} else {

conditionSatisfied = true;

}

if (conditionSatisfied) {

// For GET and HEAD, we should respond with

// 304 Not Modified.

// For every other method, 412 Precondition Failed is sent

// back.

if ( ("GET".equals(request.getMethod()))

|| ("HEAD".equals(request.getMethod())) ) {

response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

response.setHeader("ETag", eTag);

return false;

}

response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);

return false;

}

}

return true;

}

这里:

String eTag = resourceAttributes.getETag();

String headerValue = request.getHeader("If-None-Match");

这两句比较简单,就是分别从服务器缓存和http请求头中中取出etag。

接着判断这两个etag如果相等,则conditionSatisfied为true,会执行到以下语句:

if (conditionSatisfied) {

// For GET and HEAD, we should respond with

// 304 Not Modified.

// For every other method, 412 Precondition Failed is sent

// back.

if ( ("GET".equals(request.getMethod()))

|| ("HEAD".equals(request.getMethod())) ) {

response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

response.setHeader("ETag", eTag);

return false;

}

response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);

return false;

}

这段语句中可以发现,如果资源未改变的情况下,并且请求方式为GET或者HEAD时,会返回304状态码。否则返回一个412状态码,同样不会返回资源内容。

如果上述最终

if ((request.getHeader("If-None-Match") == null)

&& (lastModified < headerValue + 1000))

条件不成立,即资源更新了或者是第一次请求,这里会读取当前请求资源文件,并最终放入http响应中。

tomcat缓存静态资源深入

时间: 2024-12-13 14:04:38

tomcat缓存静态资源深入的相关文章

tips 前端 阻止 浏览器缓存静态资源

手机浏览器 uc上一直表现良好 qq浏览器还有微信上网址直接打开的(一样采用qq浏览器的内核) 大量缓存了静态资源 css js 图片 等这些当出现改动了刷新网页根本没有效果 电脑端浏览器没有问题 因为部分手机端浏览器 总会出于省流量性能等因素缓存静态资源本来没有什么问题 不过这会给开发带来困扰 不适合调试 如果只是这样还好 可是还是会对生产环境造成一定影响比如当服务器端的css文件内内容有了改动 手机端浏览器却一直没有释放缓存 就会造成一些页面上出现明显的问题所以给css js jpg swf

ASP.NET Core缓存静态资源

原文:ASP.NET Core缓存静态资源 背景 缓存样式表,JavaScript或图像文件等静态资源可以提高您网站的性能.在客户端,总是从缓存中加载一个静态文件,这样可以减少对服务器的请求数量,从而减少获取页面及其资源的时间.在服务器端,由于它们的请求较少,服务器可以处理更多的客户端而无需升级硬件. 虽然缓存是一件好事,但您必须确保客户端始终运行最新版本的应用程序.当您部署下一个版本的网站时,您不希望客户端使用过时的缓存版本的文件. 方案: 为确保用户始终使用最新版本的文件,我们必须为每个文件

nginx缓存静态资源,只需几个配置提升10倍页面加载速度

nginx缓存静态资源,只需几个配置提升10倍页面加载速度 首先我们看图说话 这是在没有缓存的情况下,这个页面发送了很多静态资源的请求: 1.png 可以看到,静态资源占用了整个页面加载用时的90%以上,而且这个静态资源还是已经在我使用了nginx配置压缩以后的大小,如果没有对这些静态资源压缩的话,那么静态资源加载应该会占用这个页面展示99%以上的时间.听起来是不是已经被吓到了,但是数据已经摆在这里了,这可不是危言耸听. 然后再看看使用了nginx缓存之后的效果图: 2.png 看到没有,朋友们

nginx在windows下配置缓存服务器缓存静态资源+Tomcat集群

nginx安装目录 修改nginx.conf文件配置负载均衡配置Tomcat集群并设置动静分离 #user nobody; error_log logs/error.log; worker_processes 2; worker_rlimit_nofile 1024; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request&quo

Nginx实现动静结合(动态资源由tomcat管理: 静态资源由Nginx管理)

简单安装就不介绍了 安装:http://www.cnblogs.com/zgxz/p/7722925.html  (Nginx及Nginx负载均衡) 如果你已经安装了Nginx,可以配置三个Nginx服务(下面讲),当然你也可以安装三个Nginx 在conf的目录下拷贝两份nginx.conf 在Nginx.conf中配置 静态资源访问的Nginx的服务器 配置静态资源拦截访问的拦截 打开Nginx81.conf 进行配置 打开Nginx82.conf 进行配置 启动时启动三个Nginx.con

Nginx+Tomcat动静态资源分离

1 创建用户.用户组 1 2 3 4 useradd -g users www passwd www //设置密码,否则该用户不可用 groupadd -g 888 www //创建用户组 gpasswd -a www www //将用户www加入用户组www 2 下载nginx.pcre(处理url重写) 1 2 wget http://blog.s135.com/soft/linux/nginx_php/nginx/nginx-0.8.46.tar.gz wget http://blog.s

静态资源(JS/CSS)存储在localStorage

一.简单了解SEO SEO由英文Search Engine Optimization缩写而来, 中文意译为“搜索引擎优化”.SEO是指从自然搜索结果获得网站流量的技术和过程. 搜索引擎不优化的网站分为以下特征: 1.网页中大量采用图片或者Flash等富媒体(Rich Media)形式,没有可以检索的文本信息,而SEO最基本的就是文章SEO和图片SEO: 2.网页没有标题,或者标题中没有包含有效的关键词: 3.网页正文中有效关键词比较少(最好自然而重点分布,不需要特别的堆砌关键词): 4.网站导航

js操作serviceWorker缓存静态文件

js操作serviceWorker缓存静态文件 serviceWorker的作用就是用来做离线应用的,在手机端程序中用的较多 先看下效果 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,

静态资源缓存常用的方式

最近遇到项目优化的问题,由于项目用到的框架,函数库比较多,导致首次需要加载3.6M的文件,那么问题来了,当网络很差的时候,很多文件就会timeout.然后就挂了.所以就开始用到离线缓存,一些文件静态的函数库开始缓存起来,一些经常更新的文件每次上线加版本号更新. 下面说说离线缓存,长话短说,很简单,只要完成简单的几个步骤 1,创建一个后缀名为.appcache的文件(如:list.appcache),里面配置项也很简单,同上 CACHE MANIFEST:这里面把你需要缓存的文件列出来,注意路径哈