项目中关于用户注销问题,很是困扰,明明在退出代码中removeAttribute了,再点后退按钮还是能用上次登陆的用户正常操作,伤脑筋啊。
以下是上网查的资料,记录下来以待慢慢研究。
------------------------------------------------------------------
用户退出解决办法:
在JSP里写
<html:button property="PassWordBackOutButton" ="PassWordBackOutJava();">退出 </html:button>
VehicleDriveManageInterfaceBackOutJava()
{
location.href = "BackOut.jsp" ;
}
BackOut.jsp为我定义的清空session的代码,代码如下:
<%
session.invalidate(); //这行为清空session
response.sendRedirect("UserLogin.jsp");//这行为转到的页面,我设置转到登陆页面
%>
好,用户退出功能完成,可是退出之后,按下后退按钮,看到了登陆时看过的页面,试着往文本框里输入了值,点提交,汗,提交成功了,这个是大事了,开始找解决办法,找来找去,暂时只有禁止缓存了,禁止缓存的方法为:
在想禁止缓存的页面的 <body> </body>里加入:
<%
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires",0);
%>
即: <body>
<%
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires",0);
%>
</body>
假如不管用,可以在Filter里也加上
esponse.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires",0);
这样退出后再后退就不会访问到登陆时能看到的页面了,可是有一个缺点,就是禁止了缓存,每次执行一个页面的时候,都要重新提交,占资源,速度也会变慢,解决办法,有待进一步去发现,而且这样有一个非常重大的缺陷,就是用户在登陆的时候,假如提交了页面,再按后退的话,就会显示页面过期,所以,12月23号上班,我又改进了一下用户退出,不禁止缓存了,现在的用户退出是,用户退出之后可以访问曾看过的页面,但是不可以提交东西了,假如填写的东西满足errors的判定,一提交,就会返回到登陆页面,假如不满足errors判定的,就显示,请登陆后在进行操作。下面是实现的方法
有退出按钮的jsp
<html:button property="ProtectListBackOutButton" ="ProtectListBackOutJava();">退出 </html:button>
ProtectListBackOutJava()
{
location.href = "BackOut.jsp" ;
}
BackOut.jsp //就是有退出功能的jsp
<body>
<%
session.removeAttribute("sessionUserName");
session.removeAttribute("UserLogin.do");
session.invalidate();
response.sendRedirect("UserLogin.jsp");
response.setHeader("Cache-Control","no-store");
response.setDateHeader("Expires",0);
response.setHeader("Pragma","no-cache");
%>
</body>
相应的form
public Actis validate(ActionMapping mapping,
HttpServletRequest request) {
Actis errors = new Actis() ;
if (request.getSession().getAttribute("sessionUserName")==null ¦ ¦"".equals(request.getSession().getAttribute("sessionUserName")))
{
errors.add("error",new ActionMessage("session.null")) ;
}
else
{
// 保护名单
if(protectListBrandNumberInput==null ¦ ¦"".equals(protectListBrandNumberInput))
{
errors.add("errorProtectList",new ActionMessage("protectListBrandNumberInput.null")) ;
}
else
{
if(protectListBrandNumberInput.length()!=5)
{
errors.add("errorProtectList",new ActionMessage("protectListBrandNumberInput.leng")) ;
}
}
}
return errors;
}
相应action:
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
{
if (request.getSession().getAttribute("sessionUserName")==null ¦ ¦"".equals(request.getSession().getAttribute("sessionUserName")))
{
return mapping.findForward("sessionEnded");
}
else
{
} //这个if要写在form的前面,这样可以省去不少资源,在form之前判定有没有登陆,假如没登陆就可以不用去调用form了
ProtectListForm protectListForm = (ProtectListForm) form;
好了,先就做成这样,等我有了更好的办法的时候再更新
在朋友的帮助下,用户退出又有更好的解决办法拉,用户退出之后,在form里验证也可转发到其他页面了,把下面这段代码加进form里就可以了
public Actis validate(ActionMapping mapping,
HttpServletRequest request,HttpServletResponse response) {
Actis errors = new Actis() ;
if (request.getSession().getAttribute("sessionUserName")==null ¦ ¦"".equals(request.getSession().getAttribute("sessionUserName")))
{
errors.add("error",new ActionMessage("session.null")) ;
mapping.findForward("sessionEnded");
}
大功告成,下一步就是如何在用户退出之后在form里干掉缓存了,其实不干掉也行了的,看个人喜好和老总要求了
---------------------------------------------下面可不看-----------------------------------------------------
下面是今天找到的有用的东西,也粘上来吧
登录过后,重新定向到.jsp,而不是让浏览器的URL保持在某个Serlvet或者.do这样的路径.
<%
if (用户已经登录) {
%>
<>
location.href = "default.jsp ";
</>
<%
}
%>
原理:
再多定义一个空的login.jsp,登录成功之后,直接跳转到此页面,
而把原来登录成功的路径在这个login.jsp中用
<>
location.href = "default.jsp ";
</>
跳过去,这样,退出之后再点 "后退 "/ "刷新 ",提交就会定向到此login.jsp,
而这个jsp是需要经过过滤器的,因为session已经被清空,所以就过滤掉了!!
即登录时多经过了一个起中间桥梁的jsp页面,
浏览器缓存内幕及解决方案
在下面三种不同的情况下,浏览器的缓存情况不同:
1).Servlet没有覆盖getLastModified方法,响应消息中无LastModified头字段,在浏览器缓存的文档无“上次修改时间”.
2).有getLastModified方法,响应消息中有LastModified头字段,但返回时间晚于缓存文档“上次修改时间”
3).有getLastModified方法,响应消息中有LastModified头字段,但返回时间早于等于缓存文档“上次修改时间”
后退、前进、转到(手工输入后按回车) 通过超链接访问 刷新
1)不发请求,直接使用缓存 发出请求 发出请求
2)不发请求,直接使用缓存 不发请求 发出请求,返回200
3)不发请求,直接使用缓存 不发请求 发出请求,返回304
2、如何禁止Servlet的缓存?(张老师JavaWeb书第236页)
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
3、如何禁止JSP页面的缓存?
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
< http-equiv="pragma" content="no-cache">
< http-equiv="cache-control" content="no-cache">
< http-equiv="expires" content="0">
4、如何禁止静态页面的缓存?(张老师JavaWeb书第238页)
< http-equiv="pragma" content="no-cache">
< http-equiv="cache-control" content="no-cache">
< http-equiv="expires" content="0">
静态页面被禁止后,刷新浏览器返回304
JSP页面被禁止后,刷新浏览器返回200
web开发中的缓存问题的研究
一般情况下,浏览器都会缓存已经访问过的页面内容,关于如何禁止浏览器缓存的介绍,在网上到处都有相关的文章,但是,关于浏览器如何利用缓存,如何处理缓存的讲解,却鲜有人谈及。我一直为这个问题所困惑,这个问题也是绝大多数有经验的WEB开发人员所共同面临的问题,我有些朋友已做过几十个大大小小的WEB项目,当与他们交流这些问题时,他们虽然也在项目中碰到和解决过这些问题,但由于没有足够的时间和精力来仔细思考这些问题的原因和细节,他们对这些问题始终也是一知半解、含糊不清,而现在又很少关于这些问题的专门和具体讲解,我最近用了两天的时间,把浏览器缓存的问题透彻地研究了一翻,主要包括一下方面的细节。
1 如何禁止浏览器缓存,这是最简单的问题,本来羞于在此讲解,但是为了完整性,不妨将其列为一个知识点。
2 浏览器在访问已缓存过的资源时,它在什么情况下会向服务器发送请求?在什么情况下根本就不向服务器发送请求。这与浏览器的缓存设置有关!但是,由于几乎所有人的浏览器都是采用的默认设置,所以,重点应该放在分析浏览器的默认缓存设置的研究上。
3 当通过其他网页文档中的超链接来访问某一个已经缓存过的资源时,浏览器是否要向服务器发出访问请求?假如不发,则会出现一个问题:当销售一件商品后再回到商品库存的显示页面时,看到的还将是先前看到的内容,而不是更新的库存数据。但是,在访问一个普通的HTML文件时,假如浏览器每次都向服务器发送访问请求,效率就会相对低下,这就失去了缓存的意义和价值。所以,结论应是浏览器访问动态页面时不能使用缓存,而访问静态页面时应该使用缓存,但是,仅仅根据被访问页面的资源名称,浏览器是无法知道商品库存的显示页面是属于动态内容,还是属于静态内容。浏览器是根据什么方式来判定它缓存的资源是动态的,还是静态的呢?在什么请求下,它会对缓存的资源总是发出新的请求呢?
4。对于缓存的内容,即使浏览器向服务器发送了请求,但服务器在接收到请求后,可能不会返回内容,而是让浏览器继续使用缓存的内容,这在实际应用中有什么好处呢?如何处理其具体细节呢?
5。服务器端也有缓存,当服务器接收到浏览器的请求后,假设它返回响应内容,但返回的响应内容可能不是最新的内容,而很可能是一个旧的缓存版本,这又是怎么回事呢?
浏览器缓存内幕与getLastModified方法
在HttpServlet类中定义了一个getLastModified方法,其完整语法定义如下:
protected long getLastModified(HttpServletRequest req)
其中的返回值表示自1970年1月1日的0点0分0秒开始计算的一个毫秒数,HttpServlet类中定义的getLastModified方法总是返回一个负数,在HttpServlet子类中可以对这个方法进行覆盖,以便返回一个代表当前输出的响应内容的修改时间,HttpServlet类的service方法可以根据这个返回值在响应消息中自动生成Last-Modified头字段。
一般情况下,浏览器都会缓存已经访问过的页面内容,getLastModified方法的返回值可以影响浏览器如何处理和利用缓存内容。在具体了解getLastModified方法的应用之前,应该先对浏览器的缓存机制有所了解。
单击IE浏览器的“工具“Internet选项”菜单,打开“Internet选项”对话框,接着再单击“常规”选项卡中的“Internet临时文件”栏中的“设置”按钮,打开“设置”对话框。“设置”对话框的“Internet临时文件夹”栏中,可以看到浏览器保存所有缓存页面内容的文件夹的完整目录名称。
“每次访问此页时检查”选项表示浏览器每次访问一个页面时,不管浏览器是否缓存过此页面,都要向服务器发出访问请求。这种设置的优点是实时性很强,肯定能够访问到网页的最新内容,但是假如网页内容很少更新,这种设置的访问效率就比较低了。
“每次启动Internet Explorer时检查”选项表示在浏览器的每次启动运行期间,在第一次访问一个页面时,不管浏览器是否缓存过此页面,都要向服务器发出访问请求,但是在浏览器的本次启动运行期间对该页面的后续访问,浏览器将不再向服务器发出访问请求,而是直接使用缓存中的内容。这种设置具有较高的访问效率,同时也兼顾了较好的实时性,它可以保证每次启动浏览器后看到的都是最新的网页内容。
“自动”选项与“每次启动Internet Explorer时检查”选项的功能相似,只是对图像的访问有所不同,假如随着时间的推移,浏览器发现网页上的图像更新并不频繁,这样,即使浏览器在对某个已缓存的图像执行本次启动运行以来的第一次访问时,它也不一定会向服务器发出访问请求,而是干脆直接使用缓存中的内容。“自动”选项是浏览器的默认设置,所以,几乎所有人的浏览器都是按照这种方式工作的,这个选项的作用和意义应该成为读者熟悉的重点。
“不检查”选项表示浏览器不管在什么情况下访问一个页面时,只要能够在本地找到此页面的缓存信息,浏览器就不会向服务器发出访问请求,而是直接使用缓存的内容。这种设置的优点是访问效率很高,但是假如服务器端的网页内容更新后,浏览器看到的内容很可能是过期的内容。
在浏览器的“检查所存网页的较新版本”的功能项采用默认的“自动”设置项的情况下,假如浏览器刚刚访问过一个网页,服务器端就更新了这个网页的内容,当浏览在关闭前又重新访问这个页面时,用户看到的将不是更新的网页内容,而是过期的网页内容。为了提高浏览效率,在访问静态的网页内容时,这么一点小概率的过期信息还是应该答应的,并且这些过期信息也不会造成什么不好的后果,就像你偶然有一次看到了前一天发生的新闻,而不是当天的新闻,这又有什么问题呢?可是,假如浏览器访问的是一个动态网页,这本来就要求浏览器在其整个运行期间的每次访问都能看到最新的内容,例如,销售一件商品后再回到商品库存的显示页面时,看到的就应该是更新的库存数据,而不应该是先前看到的内容。仅仅根据被访问页面的资源名称,浏览器是无法知道商品库存的显示页面是属于动态内容,还是属于静态内容。对于这种情况,浏览器将根据响应消息中是否包含Last-Modified头字段来进行处理,假如响应消息中没有包含Last-Modified头字段,它将在每次访问此页面时都向服务器发出访问请求,否则,它仅在每次启动运行后的第一次访问此页面时才向服务器发出访问请求,而在启动运行期间对此页面的后续访问都不再向服务器发出访问请求。
响应消息中的Last-Modified头字段可用于指定响应内容的最后更新时间,当客户机缓存此文档内容后,它在以后的请求消息中将根据Last-Modified头字段指定的时间来生成If-Modified-Since请求头字段,以指出缓存文档的最后更新时间。只有文档的修改时间比If-Modified-Since请求头指定的时间新时,服务器才会返回文档内容。假如自从If-Modified-Since指定的时间以来,网页内容没有发生修改,服务器将返回一个304(Not Modified)状态码来表示浏览器缓存的版本是最新的,而不会向浏览器返回文档内容,浏览器则继续使用以前缓存的内容。通过这种方式,可以在一定程度上减少浏览器与服务器之间的通信数据量,从而提高了通信效率。
HttpServlet类为If-Modified-Since请求头和Last-Modified头字段的这种应用提供了处理机制,当继续了HttpServlet类的Servlet程序接收到一个GET方式的访问请求时,HttpServlet中重载的service方法在调用doGet方法之前,它还将调用getLastModified方法,并根据getLastModified方法的返回值来决定是否调用doGet方法和在响应消息中是否生成Last-Modified头字段,具体规则如下:
当getLastModified方法返回一个负数时,不管请求消息中的情况怎样,service方法都将直接调用doGet方法来生成响应内容,这正是HTTPServlet类中定义的getLastModified方法的行为;
当getLastModified方法返回一个正数,且请求消息中没有包含If-Modified-Since请求头时(这往往出现在第对某个资源的第一次访问时),或者请求消息中包含的If-Modified-Since请求头中的时间值比getLastModified方法返回的时间值旧时,service方法将根据getLastModified方法的返回值生成一个Last-Modified头字段,然后调用doGet方法生成响应内容;
当getLastModified方法返回一个正数时,且请求消息中包含的If-Modified-Since请求头中的时间值比getLastModified方法返回的时间值新或者与之相同时,service方法将不调用doGet方法,而是向浏览器返回一个304(Not Modified)状态码表示浏览器可以使用其以前缓存的内容。