`

让servlet支持浏览器缓存

 
阅读更多

大家都知道IE等浏览器支持缓存,并且缓存策略可配置,这样可以极大提高访问服务器的性能,对于一些如JS脚本、CSS文件、图片等静态资源,已经缺省被支持,但是对于自定义Servlet,则默认情况下不支持缓存,这

是什么原因呢?如何让自定义Servlet也支持缓存呢?
    首先来了解下浏览器的缓存机制:对于所有的HTTP Get请求,浏览器会先检查客户端本地缓存是否存在,如果存在,则会在请求头中包含If-Modified-Since头信息,这个Header的值是本地缓存中资源的最后修改时间,服务端通过访问这个头信息和服务器上资源的最后修改时间进行比较,如果服务器端时间更新,则表示资源被修改了,需要重新下载,会调用doGet方法当作正常的Get请求处理,如果服务器端资源最后修改时间不大于客户端的最后修改时间,则表示资源没有修改,直接返回一个304的状态码,表示请浏览器使用自己缓存中的就行了,从而实现了缓存,减少了网络传输,提高了性能。
    但是不是这样的处理在每次请求时都会做呢?答案是否定的!其实这种处理是每个浏览器进程对相同的请求只会做一次,第一次检查完版本后对于后续相同的请求根本不会向服务器发任何请求,直接从客户端缓存中取资源。这样就更进一步提高了性能。
    好了,明白了浏览器的缓存原理后,我们来看下如何让我们自己写的Servlet也能够被浏览器识别并缓存呢?其实这种处理在Servlet的基类中已经处理好了,实现者只需要提供一个最后修改时间的机制就行了。先来看下

基类(HttpServlet)中是如何实现的(反编译代码):
 

  1. protected void service(HttpServletRequest req, HttpServletResponse resp)  
  2.         throws ServletException, IOException  
  3.     {  
  4.         String method = req.getMethod();  
  5.         if(method.equals("GET"))  
  6.         {  
  7.             long lastModified = getLastModified(req);  
  8.             if(lastModified == -1L)  
  9.             {  
  10.                 doGet(req, resp);  
  11.             } else  
  12.             {  
  13.                 long ifModifiedSince = req.getDateHeader("If-Modified-Since");  
  14.                 if(ifModifiedSince < (lastModified / 1000L) * 1000L)  
  15.                 {  
  16.                     maybeSetLastModified(resp, lastModified);  
  17.                     doGet(req, resp);  
  18.                 } else  
  19.                 {  
  20.                     resp.setStatus(304);  
  21.                 }  
  22.             }  
  23.         } else  
  24.         ......  
  25.     }  

 

从上面的代码实现就可以看出,取最后修改时间是调用getLastModifyed方法,这是一个保护的方法,定义如下:
protected long getLastModified(HttpServletRequest req)
    {
        return -1L;
    }
所以要想Servlet能够支持浏览器缓存,只需要把这个方法重新实现为返回正确的最后修改时间就行了。
举个例子:
我们实现一个Servlet,产生一个服务器端的Java类的客户端JavaScript代理,这被一些Ajax框所使用,
整个类如下所示,覆盖实现了getLastModifyed方法:

  1. public class RemoteServlet extends HttpServlet {  
  2.     public RemoteServlet() {  
  3.     }  
  4.     /** 
  5.      * 记录类的最近访问时间. 
  6.      */  
  7.     private static final Map DATEMAP=new HashMap();  
  8.     /* 
  9.      * (non-Javadoc) 
  10.      *  
  11.      * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, 
  12.      *      javax.servlet.http.HttpServletResponse) 
  13.      */  
  14.     protected void doGet(HttpServletRequest request,  
  15.             HttpServletResponse response) throws ServletException, IOException {  
  16.         response.setContentType("application/x-javascript;charset=GBK");  
  17.         String path = request.getServletPath();  
  18.         int index = path.lastIndexOf('/');  
  19.         path = path.substring(index + 1);  
  20.         PrintWriter writer = response.getWriter();  
  21.         String scriptStr = "";  
  22.         try {  
  23.             //如果不存在,则添加当前时间   
  24.             if(!DATEMAP.containsKey(path)){  
  25.                 DATEMAP.put(path,new Date());  
  26.             }  
  27.             scriptStr = ClassToRemoteUtil.ClassToRemote(path);  
  28.         } catch (Exception e) {  
  29.             if(log.isErrorEnabled()){  
  30.                 log.error(e.getMessage(),e);  
  31.             }  
  32.             scriptStr="alert('产生远程服务代理"+path+"失败:"+e.getMessage()+"');";  
  33.         }  
  34.         writer.write(scriptStr);  
  35.     }  
  36.   
  37.     /** 
  38.      * {@inheritDoc} 
  39.      * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest) 
  40.      */  
  41.     protected long getLastModified(HttpServletRequest req) {  
  42.         String path = req.getServletPath();  
  43.         int index = path.lastIndexOf('/');  
  44.         path = path.substring(index + 1);  
  45.         Date lastModifyDate=(Date)DATEMAP.get(path);  
  46.         if(lastModifyDate==null){  
  47.             lastModifyDate=new Date();  
  48.             DATEMAP.put(path, lastModifyDate);  
  49.         }  
  50.         return lastModifyDate.getTime();  
  51.     }  
  52.   
  53. }  

 

这样处理以后,这个Servlet的所有请求都能够被浏览器缓存支持。这个Servlet处理的请求为http://xxxx.xxxx.xxx.xx:port/xxxx/classfullname.ro,
则所有的.ro请求都可以用到浏览器缓存,从而提高性能。

分享到:
评论

相关推荐

    Web应用与开发作业

    (2)有3个http响应头字段可以禁止浏览器缓存当前页面,它们在Servlet中的示例代码如下。 response.setDateHeader("Expires",-1); response.setHeader("Cache-Control","no-cache"); response.setHeader("Pragma",...

    JSP 开发之Servlet解决网页缓存问题

    JSP 开发之Servlet解决网页缓存问题 (1)我们为什么要防止游览器页面缓存的问题: 所以在不需要缓存的页面中需要实现不缓存页面; 代码如下: package com.lc.HttpTest; import java.io.IOException; import ...

    java开发趣味人生预测(jsp+servlet)

    使用java中的jsp及servlet开发的有趣项目——趣味人生...主要技术:jsp+servlet将表单数据提交到后台,,用java修改图片,将表单数据添加到图片上,创建图片缓存对象。在利用jsp+servlet将修改后的图片返回到浏览器。

    html5-cache-manifest-servlet:Servlet 用于自动生成 cache.manifest(HTML5 中的离线模式)文件并在缓存资源更改时更新它

    缓存清单 Servlet介绍HTML5 提供了很棒的功能此功能基于cache.manifest文件,浏览器使用该文件来确定应在离线模式下访问哪些资源。 每次打开页面浏览器时,都使用页面和资源的缓存版本,但是在后台检查cache....

    java web在线考试系统,框架:html + js + css + jsp + servlet

    当出现乱码在添加拦截浏览器不要清除缓存就可以了 必须使用chrome浏览器支持前端h5框架 sql尽量使用5.6或这更低的版本 角色介绍: 管理员 admin 123456 普通用户 www 123456 模块介绍: 管理员 登录模块 系统功能...

    利用Cookie实现十天免登录

    浏览器接收到来自服务器的Cookie数据之后默认将其保存在浏览器缓存中(如果浏览器关闭,缓存消失,Cookie数据消失),只要浏览器不关闭,当我们下一次发送“特定”请求的时候,浏览器负责将Cookie数据发送给WEB...

    在线考试系统平台设计,框架:html + js + css + jsp + servlet + java + mysql

    当出现乱码在添加拦截浏览器不要清除缓存就可以了 必须使用chrome浏览器支持前端h5框架 sql尽量使用5.6或这更低的版本 角色介绍: 管理员 admin 123456 普通用户 www 123456 模块介绍: 管理员 登录模块 系统功能...

    网络考试系统平台设计,框架:html + js + css + jsp + servlet + java + mysql

    当出现乱码在添加拦截浏览器不要清除缓存就可以了 必须使用chrome浏览器支持前端h5框架 sql尽量使用5.6或这更低的版本 角色介绍: 管理员 admin 123456 普通用户 www 123456 模块介绍: 管理员 登录模块 系统功能...

    5个Servlet过滤器实例源码(JSP)

    Servlet过滤器大全,各种详细使用的代码! 一、字符编码的过滤器 二、使浏览器不缓存页面的过滤器 三、检测用户是否登陆的过滤器 四、资源保护过滤器 五 利用Filter限制用户浏览权限

    Java高并发高性能分布式框架从无到有微服务架构设计.doc

    高并发- HTTP缓存浏览器缓存是指当我们使用浏览器访问一些网站页面或者http服务时,根据服 务端返回的缓存设置响应头将响应内容缓存到浏览器,下次可以直接使用缓存内容或者 仅需要去服务端验证内容是否过期即可。...

    scalikejdbc-mapper-generator-core_2.10-2.1.0.zip

    javaee-cache-filter.zip,JavaEE缓存过滤器是一个servlet过滤器,允许您设置HTTP报头,以便启用或禁用浏览器缓存。

    SpringShiro分布式缓存版

    目的就是让用户整个访问过程中,项目读取到用户浏览器的同一个cookie..就会有一样的jessessionid.. --&gt; &lt;!-- sessionIdCookie的实现,用于重写覆盖容器默认的JSESSIONID --&gt; ...

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

    在默认的 web.xml 中,配置了一个 DefaultServlet 用于处理静态资源,它支持缓存和断点续传。 DefaultServlet 的基本处理过程如下: 查找资源是否存在缓存 检查是否满足可选 If 头域指定的条件 设置响应头域,如 ...

    Java项目源码之聊天系统的实现(java+applet).zip

    Servlet:使用Java Servlet技术实现服务器端的业务逻辑和数据处理,接收和响应客户端的请求。 WebSocket:采用WebSocket技术实现客户端与服务器之间的实时双向通信,支持消息的实时推送。 数据库:选择适当的数据库...

    Wap技术初级教程、中级教程

    HTTP 1.1是一个基于文本的互联网实体信息交互主流协议,这里的实体可以是WAP兼容浏览器之类的用户终端,可以是WAP网关之类的代理服务器,也可以是Java servlet之类的源服务器程序。它们之间的交互信息就是两大类:...

    Java项目源码之家庭理财系统的实现(java+applet).zip

    Servlet:使用Java Servlet技术实现服务器端的业务逻辑和数据处理,接收和响应客户端的请求。 数据库:选择适当的关系型数据库(如MySQL、PostgreSQL等)存储用户信息、财务记录和预算数据。 前端技术:结合HTML、...

    java开源包1

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    java开源包11

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

    java开源包2

    1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. ...

Global site tag (gtag.js) - Google Analytics