`

tomcat和jetty对静态资源的处理和客户端缓存的处理

 
阅读更多

tomcat和jetty对静态资源的处理和客户端缓存的处理

 

原文链接:http://www.javaarch.net/jiagoushi/867.htm

 

这两个默认servlet名称都是defaultservlet,然后在web.xml中就可以添加下面的配置让应用支持都静态资源的处理,对应的这些静态资源的目录则是在webapp根目录下,这里其实可以不用配置servlet名称,对于名称为default的url,tomcat和jetty都会作为静态资源文件处理

 

	<servlet-mapping>
     	<servlet-name>default</servlet-name>
    	 <url-pattern>*.css</url-pattern>
	</servlet-mapping>
	 
	<servlet-mapping>
	    <servlet-name>default</servlet-name>
	    <url-pattern>*.gif</url-pattern>
	 </servlet-mapping>
	    
	 <servlet-mapping>
	     <servlet-name>default</servlet-name>
	     <url-pattern>*.jpg</url-pattern>
	 </servlet-mapping>
	    
	 <servlet-mapping>
	     <servlet-name>default</servlet-name>
	     <url-pattern>*.js</url-pattern>
	 </servlet-mapping>
	 
	 <servlet-mapping>
	     <servlet-name>default</servlet-name>
	     <url-pattern>*.swf</url-pattern>
	 </servlet-mapping>



那么我们来看看tomcat和jetty对静态资源的客户端缓存的处理逻辑:


tomcat,tomcat在default的servlet支持一些参数,如果有需要那么就需要配置servlet了,

 

 

	<servlet>  
	  <servlet-name>default</servlet-name>  
	  <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>  
	  <init-param>  
		  <param-name>debug</param-name>  
		  <param-value>0</param-value>  
	  </init-param>  
	  <init-param>  
		  <param-name>listings</param-name>  
		  <param-value>false</param-value>  
	  </init-param>  
	  <load-on-startup>1</load-on-startup>  
	</servlet> 


在对于静态资源处理的客户端缓存的代码如下

 

 

	// ETag header
    response.setHeader("ETag", cacheEntry.attributes.getETag());

    // Last-Modified header
    response.setHeader("Last-Modified", cacheEntry.attributes.getLastModifiedHttp());


这里的etag计算规则如下:

 

 

	long contentLength = getContentLength();
	long lastModified = getLastModified();
	if ((contentLength >= 0) || (lastModified >= 0)) {
		weakETag = "W/\"" + contentLength + "-" +
				   lastModified + "\"";
	}
	



输出的reponse header如下:

 

 

	HTTP/1.1 200 OK
	Server: Apache-Coyote/1.1
	Accept-Ranges: bytes
	ETag: W/"7482-1371188756000"
	Last-Modified: Fri, 14 Jun 2013 05:45:56 GMT
	Content-Type: text/css;charset=GBK
	Content-Length: 7482
	Date: Sun, 16 Jun 2013 07:05:37 GMT


第二次请求时,会先对reqeust的etag和last-modified进行比对,如果没更新的话则返回304

 

 

protected ArrayList<Range> parseRange(HttpServletRequest request,
            HttpServletResponse response,
            ResourceAttributes resourceAttributes) throws IOException {

        // Checking If-Range
        String headerValue = request.getHeader("If-Range");

        if (headerValue != null) {

            long headerValueTime = (-1L);
            try {
                headerValueTime = request.getDateHeader("If-Range");
            } catch (IllegalArgumentException e) {
                // Ignore
            }

            String eTag = resourceAttributes.getETag();
            long lastModified = resourceAttributes.getLastModified();

            if (headerValueTime == (-1L)) {

                // If the ETag the client gave does not match the entity
                // etag, then the entire entity is returned.
                if (!eTag.equals(headerValue.trim()))
                    return FULL;

            } else {

                // If the timestamp of the entity the client got is older than
                // the last modification date of the entity, the entire entity
                // is returned.
                if (lastModified > (headerValueTime + 1000))
                    return FULL;

            }

        }
	


第二次返回:

 

 

	HTTP/1.1 304 Not Modified
	Server: Apache-Coyote/1.1
	ETag: W/"2640-1371187966000"
	Date: Sun, 16 Jun 2013 07:23:27 GMT


那么这里对静态资源浏览器就自动能够缓存起来了。当然tomcat和jetty服务器也会对静态资源进行缓存。


jetty对这个处理也差不多,不过jetty对于静态资源的缓存策略可以做更多参数设置,这些参数都是在web.xml配置servlet的时候可以进行设置的。

 

 

_cacheControl=getInitParameter("cacheControl");

        String resourceCache = getInitParameter("resourceCache");
        int max_cache_size=getInitInt("maxCacheSize", -2);
        int max_cached_file_size=getInitInt("maxCachedFileSize", -2);
        int max_cached_files=getInitInt("maxCachedFiles", -2);
        if (resourceCache!=null)
        {
            if (max_cache_size!=-1 || max_cached_file_size!= -2 || max_cached_files!=-2)
                LOG.debug("ignoring resource cache configuration, using resourceCache attribute");
            if (_relativeResourceBase!=null || _resourceBase!=null)
                throw new UnavailableException("resourceCache specified with resource bases");
            _cache=(ResourceCache)_servletContext.getAttribute(resourceCache);

            LOG.debug("Cache {}={}",resourceCache,_cache);
        }

        _etags = getInitBoolean("etags",_etags);



处理代码:


写header

 

 

    /* ------------------------------------------------------------ */
    protected void writeHeaders(HttpServletResponse response,HttpContent content,long count)
    throws IOException
    {        
        if (content.getContentType()!=null && response.getContentType()==null)
            response.setContentType(content.getContentType().toString());

        if (response instanceof Response)
        {
            Response r=(Response)response;
            HttpFields fields = r.getHttpFields();

            if (content.getLastModified()!=null)
                fields.put(HttpHeader.LAST_MODIFIED,content.getLastModified());
            else if (content.getResource()!=null)
            {
                long lml=content.getResource().lastModified();
                if (lml!=-1)
                    fields.putDateField(HttpHeader.LAST_MODIFIED,lml);
            }

            if (count != -1)
                r.setLongContentLength(count);

            writeOptionHeaders(fields);
            
            if (_etags)
                fields.put(HttpHeader.ETAG,content.getETag());
        }
        else
        {
            long lml=content.getResource().lastModified();
            if (lml>=0)
                response.setDateHeader(HttpHeader.LAST_MODIFIED.asString(),lml);

            if (count != -1)
            {
                if (count<Integer.MAX_VALUE)
                    response.setContentLength((int)count);
                else
                    response.setHeader(HttpHeader.CONTENT_LENGTH.asString(),Long.toString(count));
            }

            writeOptionHeaders(response);

            if (_etags)
                response.setHeader(HttpHeader.ETAG.asString(),content.getETag().toString());
        }
    }


判断静态资源是否修改过

 

 

 /* ------------------------------------------------------------ */
    /* Check modification date headers.
     */
    protected boolean passConditionalHeaders(HttpServletRequest request,HttpServletResponse response, Resource resource, HttpContent content)
    throws IOException
    {
        try
        {
            if (!HttpMethod.HEAD.is(request.getMethod()))
            {
                if (_etags)
                {
                    String ifm=request.getHeader(HttpHeader.IF_MATCH.asString());
                    if (ifm!=null)
                    {
                        boolean match=false;
                        if (content!=null && content.getETag()!=null)
                        {
                            QuotedStringTokenizer quoted = new QuotedStringTokenizer(ifm,", ",false,true);
                            while (!match && quoted.hasMoreTokens())
                            {
                                String tag = quoted.nextToken();
                                if (content.getETag().toString().equals(tag))
                                    match=true;
                            }
                        }

                        if (!match)
                        {
                            Response r = Response.getResponse(response);
                            r.reset(true);
                            r.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED);
                            return false;
                        }
                    }
                    
                    String ifnm=request.getHeader(HttpHeader.IF_NONE_MATCH.asString());
                    if (ifnm!=null && content!=null && content.getETag()!=null)
                    {
                        // Look for GzipFiltered version of etag
                        if (content.getETag().toString().equals(request.getAttribute("o.e.j.s.GzipFilter.ETag")))
                        {
                            Response r = Response.getResponse(response);
                            r.reset(true);
                            r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                            r.getHttpFields().put(HttpHeader.ETAG,ifnm);
                            return false;
                        }
                        
                        
                        // Handle special case of exact match.
                        if (content.getETag().toString().equals(ifnm))
                        {
                            Response r = Response.getResponse(response);
                            r.reset(true);
                            r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                            r.getHttpFields().put(HttpHeader.ETAG,content.getETag());
                            return false;
                        }

                        // Handle list of tags
                        QuotedStringTokenizer quoted = new QuotedStringTokenizer(ifnm,", ",false,true);
                        while (quoted.hasMoreTokens())
                        {
                            String tag = quoted.nextToken();
                            if (content.getETag().toString().equals(tag))
                            {
                                Response r = Response.getResponse(response);
                                r.reset(true);
                                r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                                r.getHttpFields().put(HttpHeader.ETAG,content.getETag());
                                return false;
                            }
                        }
                        
                        // If etag requires content to be served, then do not check if-modified-since
                        return true;
                    }
                }
                
                // Handle if modified since
                String ifms=request.getHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
                if (ifms!=null)
                {
                    //Get jetty's Response impl
                    Response r = Response.getResponse(response);
                                       
                    if (content!=null)
                    {
                        String mdlm=content.getLastModified();
                        if (mdlm!=null)
                        {
                            if (ifms.equals(mdlm))
                            {
                                r.reset(true);
                                r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                                r.flushBuffer();
                                return false;
                            }
                        }
                    }

                    long ifmsl=request.getDateHeader(HttpHeader.IF_MODIFIED_SINCE.asString());
                    if (ifmsl!=-1)
                    {
                        if (resource.lastModified()/1000 <= ifmsl/1000)
                        { 
                            r.reset(true);
                            r.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                            r.flushBuffer();
                            return false;
                        }
                    }
                }

                // Parse the if[un]modified dates and compare to resource
                long date=request.getDateHeader(HttpHeader.IF_UNMODIFIED_SINCE.asString());

                if (date!=-1)
                {
                    if (resource.lastModified()/1000 > date/1000)
                    {
                        response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
                        return false;
                    }
                }

            }
        }
        catch(IllegalArgumentException iae)
        {
            if(!response.isCommitted())
                response.sendError(400, iae.getMessage());
            throw iae;
        }
        return true;
    }
	


第一次访问的response header头:

 

 

	HTTP/1.1 200 OK
	Server: Apache-Coyote/1.1
	Accept-Ranges: bytes
	ETag: W/"7482-1371188756000"
	Last-Modified: Fri, 14 Jun 2013 05:45:56 GMT
	Content-Type: text/css;charset=GBK
	Content-Length: 7482
	Date: Sun, 16 Jun 2013 07:05:37 GMT

 

 


第二次访问:

 

	HTTP/1.1 304 Not Modified
	Server: Jetty(6.1.26)



 

不过处理静态资源大型网站肯定不是tomcat或者jetty,基本都是用apache或者nginx等来处理静态处理,性能更好。这里只是列出tomcat和jetyy对静态资源的处理和客户端缓存的支持。

1
3
分享到:
评论

相关推荐

    java静态文件处理

    1. **使用内置容器**:例如Tomcat、Jetty等Java应用服务器都内置了对静态文件的支持。当请求到达服务器时,如果路径匹配到静态资源,服务器会直接返回该文件,而无需执行任何Java代码。配置Web应用的`web.xml`文件,...

    Tomcat无法加载css和js等静态资源文件的解决思路

    首先,如果你的环境中同时配置了Apache服务器和Tomcat,那么可能由于配置不当导致静态资源请求没有正确地转发到Tomcat处理。Apache可以通过mod_proxy模块将HTTP请求代理到Tomcat,使得静态资源请求能够被Tomcat正确...

    Jetty权威指南.pdf

    - **轻量级**:相比于其他大型服务器如Apache Tomcat,Jetty体积更小、占用资源更少,特别适合于嵌入式环境或资源有限的设备。 - **高性能**:Jetty采用异步处理机制,能够高效处理大量并发连接,尤其适用于高负载的...

    java生存静态页面

    在配置中,我们可以指定静态资源的路径,框架会自动处理这些请求,将静态文件直接发送给客户端。 3. **构建工具优化**:在开发过程中,可以使用构建工具(如Gradle、Maven)配合前端构建工具(如Webpack、Gulp)来...

    jetty 6 指南书

    - **Jetty vs Tomcat**:相比Tomcat,Jetty 在启动速度、内存占用和并发处理能力方面有优势,更适合微服务和嵌入式场景。 - **本章小结**:强调Jetty的多功能性和灵活性,为后续章节打下基础。 2. **Jetty 初探**...

    jsp 缓存处理

    5. **浏览器缓存**:客户端浏览器会缓存静态资源和动态内容,以减少网络传输。 ### 二、JSP页面缓存的实现 #### 1. 服务端方法 服务端通过设置HTTP响应头控制浏览器缓存策略: ```java response.setHeader(...

    需要伪静态处理jar包

    这个过滤器可以集成到Java应用服务器,如Tomcat、Jetty等,对HTTP请求进行拦截和修改。通过配置`urlrewriterfilter`的规则文件,开发者可以定义一系列的URL转换规则,比如将`/product?id=123`转换为`/product/123....

    jetty指导书

    Jetty的安装和启动相对简单,但为了更好地利用Jetty的强大功能,还需要对配置文件有深入的理解,并掌握在不同操作系统下的启动控制方法。 #### 三、Jetty架构 **3.1 架构概述** Jetty采用了模块化的架构设计,...

    java 静态页面开发

    在Java中,开发静态页面主要使用Tomcat或Jetty等Web服务器,这些服务器可以托管静态资源。当用户请求一个静态页面时,服务器会直接将预先编译好的文件发送到客户端,而不需要Java后端进行任何处理。对于初学者来说,...

    Jetty中文手册打包下载

    9. **性能优化**:Jetty提供了各种性能优化选项,包括GZIP压缩、静态资源缓存、连接池管理等。 10. **错误处理与日志**:Jetty有内置的错误页面和日志系统,便于调试和问题排查。 通过“Jetty中文手册”,读者可以...

    Tomcat 5.5 中文文档 (html)

    4. **连接器(Connector)**:Tomcat的连接器负责处理客户端的请求和发送响应,如HTTP/1.1连接器,可以通过配置server.xml来调整参数,如最大线程数、超时设置等。 **三、Tomcat安全管理** 1. **用户和角色管理**...

    jetty使用文档

    - 缓存优化:利用Last-Modified和Cache-Control提高客户端缓存利用率。 17. **异步Servlet、Ajax、Comet**:支持异步处理,提高响应速度。 18. **嵌入Jetty**:将Jetty直接嵌入到Java应用程序中,简化部署流程。 ...

    web容器示例程序

    与Tomcat不同,Jetty支持非阻塞I/O(NIO),在处理高并发场景时,能更有效地利用系统资源,提高吞吐量。这也是描述中提到的“NOI”。 Resin,则是一个更全面的企业级Web容器,它的性能在某些方面甚至超过Tomcat和...

    tomcat6.0.18

    - Tomcat可以与Apache HTTP Server通过mod_proxy模块集成,实现负载均衡和更好的静态内容处理能力。 - 它也可以与其他应用服务器,如Jetty或JBoss,一起作为混合部署环境的一部分。 8. **故障排查**: - 当遇到...

    《Jetty6_指南书》

    - **缓存策略**: 使用`Cache-Control`和`Last-Modified`头优化浏览器缓存。 - **高负载服务器**: 对于高负载服务器的特殊配置建议。 - **Linux下的配置**: 如何在Linux环境下调整最大连接数等配置。 #### 十四、...

    selfWebServer(java).rar_cgi_java web_web服务器_静态网页

    Java Web服务器通常基于Servlet容器,如Tomcat、Jetty等。Servlet是Java中用于处理HTTP请求的接口,服务器接收到请求后,会调用相应的Servlet进行处理。在这个个人Web服务器中,开发者可能实现了自定义的Servlet来...

    tomcat out of memory

    标题中的“tomcat out of memory”是一个常见的Java应用服务器(Tomcat)运行时的问题,意味着Tomcat在处理请求过程中耗尽了可用的内存资源,导致应用程序崩溃或性能急剧下降。这种情况通常由几个因素引起,包括但不...

    How Tomcat Work 第一章 实例应用

    10. **性能优化**:包括调整线程池大小、启用压缩、减少内存泄漏、缓存静态资源等。例如,通过修改`server.xml`中的`Executor`元素来定制线程池参数。 通过本章的学习,读者不仅可以了解Tomcat的基本工作流程,还能...

    [课堂课件讲解]Java微服务实践-Spring Boot Web篇(上).pptx

    Java Web服务器如Tomcat和Jetty在处理静态内容时可能不如这些专门的Web服务器高效,原因在于内存占用、垃圾回收机制等因素。 为了优化静态内容的性能,可以使用标准技术,如: - **资源变化检测**:通过响应头`...

    Tomcat面试专题及答案.pdf

    以上是对Tomcat的一些核心知识点的梳理,对于面试者来说,深入理解这些概念和机制,能够有效地展示自己的专业技能。在实际工作中,根据项目需求和性能指标,灵活运用和调整Tomcat的配置,是每个合格的Java Web开发者...

Global site tag (gtag.js) - Google Analytics