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对静态资源的处理和客户端缓存的支持。

你可能感兴趣的:(tomcat)