`
zyc1006
  • 浏览: 133878 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

如何解决点击网页后退提示警告的问题

    博客分类:
  • Java
 
阅读更多

http://hi.baidu.com/litkinger/blog/item/fb8763f8bc04fd0cd8f9fd74.html

摘要

在一个有密码保护的Web应用当中,正确妥善的处理用户退出过程并不仅仅只需要调用HttpSession对象的invalidate()方法,因为现在大部分浏览器上都有后退(Back)和前进(Forward)按钮,允许用户后退或前进到一个页面。

在用户退出一个Web应用之后,如果按了后退按钮,浏览器把缓存中的页面呈现给用户,这会使用户产生疑惑,他们会开始担心他们的个人数据是否安全。

实际上,许多Web应用会弹出一个页面,警告用户退出时关闭整个浏览器,以此来阻止用户点击后退按钮。还有一些使用JavaScript,但在某些客户端浏览器中这却不一定起作用。这些解决方案大多数实现都很笨拙,且不能保证在任何情况下都100%有效,同时,它还要求用户有一定的操作经验。

这篇文章以简单的程序示例阐述了正确解决用户退出问题的方案。首先描述了一个理想的密码保护Web应用,然后以示例程序解释问题如何产生并讨论解决问题的方案。文章虽然是针对JSP进行讨论阐述,但作者所阐述的概念很容易理解而且能够为其他Web技术所采用。最后,用Jakarta Struts更为优雅地解决用户退出问题。文中包含JSP和Struts的示例程序。

大部分Web应用不会包含像银行账户或信用卡资料那样机密的信息,但是一旦涉及到敏感数据,就需要我们提供某些密码保护机制。例如,在一个工厂当中,工人必须通过Web应用程序访问他们的时间安排、进入他们的培训课程以及查看他们的薪金等等。此时应用SSL(Secure Socket Layer)就有些大材小用了(SSL页面不会在缓存中保存,关于SSL的讨论已经超出本文的范围)。但是这些应用又确实需要某种密码保护措施,否则,工人(在这种情况下,也就是Web应用的使用者)就可以发现工厂中所有员工的私人机密信息。

类似上面的情况还包括位于公共图书馆、医院、网吧等公共场所的计算机。在这些地方,许多用户共同使用几台计算机,此时保护用户的个人数据就显得至关重要。 同时应用程序的良好设计与实现对用户专业知识以及相关培训要求少之又少。

让我们来看一下现实世界中一个完美的Web应用是怎样工作的:

1、用户在浏览器中输入URL,访问一个页面。

2、Web应用显示一个登陆页面,要求用户输入有效的验证信息。

3、用户输入用户名和密码。

4、假设用户提供的验证信息是正确的,经过了验证过程,Web应用允许用户浏览他有权访问的区域。

5、退出时,用户点击页面的退出按钮,Web应用显示确认页面,询问用户是否真的需要退出。一旦用户点击确定按钮,Session结束,Web应用重新定位到登陆页面。用户现在可以放心的离开而不用担心他的信息会被泄露。

6、另一个用户坐到了同一台电脑前。他点击后退按钮,Web应用不应该显示上一个用户访问过的任何一个页面。

事实上,Web应用将一直停留在登陆页面上,除非第二个用户提供正确的验证信息,之后才可以访问他有权限的区域。

通过示例程序,文章向您阐述了如何在一个Web应用中实现上面的功能。

一、JSP samples

为了更为有效地向您说明这个解决方案,本文将从展示一个Web应用logoutSampleJSP1中碰到的问题开始。这个示例代表了许多没有正确解决退出过程的Web应用。logoutSampleJSP1包含一下JSP页面:login.jsp, home.jsp, secure1.jsp, secure2.jsp, logout.jsp, loginAction.jsp, 和 logoutAction.jsp。其中页面home.jsp, secure1.jsp, secure2.jsp, 和 logout.jsp是不允许未经认证的用户访问的,也就是说,这些页面包含了重要信息,在用户登陆之前或者退出之后都不应该显示在浏览器中。login.jsp页面包含了用于用户输入用户名和密码的form。logout.jsp页面包含了要求用户确认是否退出的form。loginAction.jsp和logoutAction.jsp作为控制器分别包含了登陆和退出动作的代码。

第二个Web示例应用logoutSampleJSP2展示了如何纠正示例logoutSampleJSP1中的问题。但是第二个示例logoutSampleJSP2自身也是有问题的。在特定情况下,退出问题依然存在。

第三个Web示例应用logoutSampleJSP3对logoutSampleJSP2进行了改进,比较妥善地解决了退出问题。

最后一个Web示例logoutSampleStruts展示了JakartaStruts如何优雅地解决退出问题。

二、Login action

解决方法便是引入用户自定义的安全实现机制,这就提供了更大的灵活性。

在用户自定义的认证方法中,普遍采用的方法是从用户提交的form中获得用户输入的认证信息,然后到诸如LDAP (lightweight directory access protocol)或关系数据库(relational database management system, RDBMS)的安全域中进行认证。如果用户提供的认证信息是有效的,登陆动作在HttpSession对象中保存某个对象。HttpSession存在着保存的对象则表示用户已经登陆到Web应用当中。为了方便起见,本文所附的示例只在HttpSession中保存一个用户名以表明用户已经登陆。清单1是从loginAction.jsp页面中节选的一段代码以此讲解登陆动作:

清单1

//...
//initialize RequestDispatcher object; set forward to home page by default
RequestDispatcher rd = request.getRequestDispatcher( "home.jsp" );

//Prepare connection and statement
rs = stmt.executeQuery( "select password from USER where userName = '" + userName + "'" );
if (rs.next()) {
//Query only returns 1 record in the result set;
//Only 1 password per userName which is also the primary key
if (rs.getString( "password" ).equals(password)) { //If valid password
session.setAttribute( "User" , userName);

//Saves username string in the session object
}
else { //Password does not match, i.e., invalid user password
request.setAttribute( "Error" , "Invalid password." );

rd = request.getRequestDispatcher( "login.jsp" );
}
} //No record in the result set, i.e., invalid username
else {

request.setAttribute( "Error" , "Invalid user name." );
rd = request.getRequestDispatcher( "login.jsp" );
}
}

//As a controller, loginAction.jsp finally either forwards to "login.jsp" or "home.jsp"
rd.forward(request, response);
//...

本文当中所附Web应用示例均以关系型数据库作为安全域,但本问所讲述的内容同样适用于其他任何类型的安全域。

三、Logout action

退出动作包含删除用户名以及调用用户的HttpSession对象的invalidate()方法。清单2是从loginoutAction.jsp中节选的一段代码,以此说明退出动作:

清单2

//... 
session.removeAttribute( "User" );
session.invalidate();
//...

四、阻止未经认证访问受保护的JSP页面

从提交的form中获取用户提交的认证信息并经过验证后,登陆动作仅仅在HttpSession对象中写入一个用户名。退出动作则刚好相反,它从HttpSession中删除用户名并调用HttpSession对象的invalidate()方法。为了使登陆和退出动作真正发挥作用,所有受保护的JSP页面必须首先验证HttpSession中包含的用户名,以便确认用户当前是否已经登陆。如果HttpSession中包含了用户名,就说明用户已经登陆,Web应用会将剩余的JSP页中的动态内容发送给浏览器。否则,JSP页将跳转到登陆页面,login.jsp。页面home.jsp, secure1.jsp, secure2.jsp和 logout.jsp均包含清单3中的代码段:

清单3

//...
String userName = (String) session.getAttribute( "User" );
if (null == userName) {
request.setAttribute( "Error" , "Session has ended. Please login." );
RequestDispatcher rd = request.getRequestDispatcher( "login.jsp" );
rd.forward(request, response);
}
//...
//Allow the rest of the dynamic content in this JSP to be served to the browser
//...

在这个代码段中,程序从HttpSession中检索username字符串。如果username字符串为空,Web应用则自动中止执行当前页面并跳转到登陆页,同时给出错误信息“Session has ended. Please log in.”;如果不为空,Web应用继续执行,把剩余的页面提供给用户,从而使JSP页面的动态内容成为服务对象。

五、运行logoutSampleJSP1

运行logoutSampleJSP1将会出现如下几种情形:

◆如果用户没有登陆,Web应用将会正确中止受保护页面home.jsp, secure1.jsp, secure2.jsp和logout.jsp中动态内容的执行。也就是说,假如用户并没有登陆,但是在浏览器地址栏中直接敲入受保护JSP页的地址试图访问,Web应用将自动跳转到登陆页面,同时显示错误信息“Session has ended.Please log in.” 
◆同样的,当一个用户已经退出,Web应用将会正确中止受保护页面home.jsp, secure1.jsp, secure2.jsp和logout.jsp中动态内容的执行。也就是说,用户退出以后,如果在浏览器地址栏中直接敲入受保护JSP页的地址试图访问,Web应用将自动跳转到登陆页面,同时显示错误信息“Session has ended.Please log in.” 
◆用户退出以后,如果点击浏览器上的后退按钮返回到先前的页面,Web应用将不能正确保护受保护的JSP页面——在Session销毁后(用户退出)受保护的JSP页会重新显示在浏览器中。然而,点击该页面上的任何链接,Web应用都会跳转到登陆页面,同时显示错误信息“Session has ended.Please log in.”

六、阻止浏览器缓存

上述问题的根源就在于现代大部分浏览器都有一个后退按钮。当点击后退按钮时,默认情况下浏览器不会从Web服务器上重新获取页面,而是简单的从浏览器缓存中重新载入页面。这个问题并不仅限于基于Java(JSP/servlets/Struts) 的Web应用当中,在基于PHP (Hypertext Preprocessor)、ASP、(Active Server Pages)、和.NET的Web应用中也同样存在。

在用户点击后退按钮之后,浏览器到Web服务器(一般来说)或者应用服务器(在java的情况下)再从服务器到浏览器这样通常意义上的HTTP回路并没有建立。仅仅只是用户,浏览器和缓存之间进行了交互。所以即使受保护的JSP页面,例如home.jsp, secure1.jsp, secure2.jsp和logout.jsp包含了清单3上的代码,当点击后退按钮时,这些代码也永远不会执行的。

缓存的好坏,真是仁者见仁智者见智。缓存事实上的确提供了一些便利,但这些便利通常只存在于静态的HTML页面或基于图形或影像的页面。而另一方面,Web应用通常是面向数据的。由于Web应用中的数据频繁变更,所以与为了节省时间从缓存中读取并显示过期的数据相比,提供最新的数据显得尤为重要!

幸运的是,HTTP头信息“Expires”和“Cache-Control”为应用程序服务器提供了一个控制浏览器和代理服务器上缓存的机制。HTTP头信息Expires告诉代理服务器它的缓存页面何时将过期。HTTP1.1规范中新定义的头信息Cache-Control在Web应用当中可以通知浏览器不缓存任何页面。当点击后退按钮时,浏览器发送Http请求道应用服务器以便获取该页面的最新拷贝。如下是使用Cache-Control的基本方法:

◆no-cache:强制缓存从服务器上获取该页面的最新拷贝;
◆no-store:在任何情况下缓存不保存该页面。

HTTP1.0规范中的Pragma:no-cache等同于HTTP1.1规范中的Cache-Control:no-cache,同样可以包含在头信息中。

通过使用HTTP头信息的cache控制,第二个示例应用logoutSampleJSP2解决了logoutSampleJSP1的问题。logoutSampleJSP2与logoutSampleJSP1不同表现在如下代码段中,这一代码段加入进所有受保护的页面中:

清单4

//...
response.setHeader( "Cache-Control" , "no-cache" );
//Forces caches to obtain a new copy of the page from the origin server
response.setHeader( "Cache-Control" , "no-store" );
//Directs caches not to store the page under any circumstance
response.setDateHeader( "Expires" , 0);
//Causes the proxy cache to see the page as "stale"
response.setHeader( "Pragma" , "no-cache" );
//HTTP 1.0 backward compatibility
String userName = (String) session.getAttribute( "User" );
if (null == userName) {
request.setAttribute( "Error" , "Session has ended. Please login." );
RequestDispatcher rd = request.getRequestDispatcher( "login.jsp" );
rd.forward(request, response);
}
//...

通过设置头信息和检查HttpSession对象中的用户名来确保浏览器不会缓存JSP页面。同时,如果用户未登陆,JSP页面的动态内容不会发送到浏览器,取而代之的将是登陆页面login.jsp。

七、运行logoutSampleJSP2

运行Web示例应用logoutSampleJSP2后将会看到如下结果:

◆当用户退出后试图点击后退按钮,浏览器不会重新显示受保护的页面,它只会显示登陆页login.jsp同时给出提示信息Session has ended. Please log in. 
◆然而,当按了后退按钮返回的页是处理用户提交数据的页面时,IE和Avant浏览器将弹出如下信息提示:

警告:页面已过期

The page you requested was created using information you submitted in a form.
This page is no longer available. As a security divcaution,
Internet Explorer does not automatically resubmit your information for you.

Mozilla和FireFox浏览器将会显示一个对话框,提示信息如下:

The page you are trying to view contains POSTDATA that has expired from cache.
If you resend the data, any action from the form carried out
(such as a search or online purchase) will be repeated.
To resend the data, click OK. Otherwise, click Cancel.

在IE和Avant浏览器中选择刷新或者在Mozilla和FireFox浏览器中选择重新发送数据后,前一个JSP页面将重新显示在浏览器中。显然的,这病不是我们所想看到的因为它违背了logout动作的目的。发生这一现象时,很可能是一个恶意用户在尝试获取其他用户的数据。然而,这个问题仅仅出现在点击后退按钮后,浏览器返回到一个处理POST请求的页面。

八、记录最后登陆时间

上述问题的发生是因为浏览器重新提交了其缓存中的数据。这本文的例子中,数据包含了用户名和密码。尽管IE浏览器给出了安全警告信息,但事实上浏览器此时起到了负面作用。

为了解决logoutSampleJSP2中出现的问题,logoutSampleJSP3的login.jsp除了包含username和password的之外,还增加了一个称作lastLogon的隐藏表单域,此表单域将会动态的被初始化为一个long型值。这个long型值是通过调用System.currentTimeMillis()获取到的自1970年1月1日以来的毫秒数。当login.jsp中的form提交时,loginAction.jsp首先将隐藏域中的值与用户数据库中的lastLogon值进行比较。只有当lastLogon表单域中的值大于数据库中的值时Web应用才认为这是个有效的登陆。

为了验证登陆,数据库中lastLogon字段必须用表单中的lastLogon值进行更新。上例中,当浏览器重复提交缓存中的数据时,表单中的lastLogon值不比数据库中的lastLogon值大,因此,loginAction将跳转到login.jsp页面,并显示如下错误信息“Session has ended.Please log in.”清单5是loginAction中节选的代码段:

清单5

//...
RequestDispatcher rd = request.getRequestDispatcher( "home.jsp" );
//Forward to homepage by default
//...
if (rs.getString( "password" ).equals(password)) { //If valid password
long lastLogonDB = rs.getLong( "lastLogon" );
if (lastLogonForm > lastLogonDB) {
session.setAttribute( "User" , userName);
//Saves username string in the session object
stmt.executeUpdate( "update USER set lastLogon= " + lastLogonForm + "
where userName = '" + userName + "'" );
}
else {
request.setAttribute( "Error" , "Session has ended. Please login." );
rd = request.getRequestDispatcher( "login.jsp" ); }
}
else { //Password does not match, i.e., invalid user password
request.setAttribute( "Error" , "Invalid password." );
rd = request.getRequestDispatcher( "login.jsp" );
}
//...
rd.forward(request, response);
//...

为了实现上述方法,你必须记录每个用户的最后登陆时间。对于采用关系型数据库安全域来说,这点可以可以通过在某个表中加上lastLogin字段轻松实现。虽然对LDAP以及其他的安全域来说需要稍微动下脑筋,但最后登陆方法很显然是可以实现的。

表示最后登陆时间的方法有很多。示例logoutSampleJSP3利用了自1970年1月1日以来的毫秒数。这个方法即使在许多人在不同浏览器中用一个用户账号登陆时也是可行的。

九、运行logoutSampleJSP3

运行示例logoutSampleJSP3将展示如何正确处理退出问题。一旦用户退出,点击浏览器上的后退按钮在任何情况下都不会在浏览器中显示受保护的JSP页面。这个示例展示了如何正确处理退出问题而不需要对用户进行额外的培训。

为了使代码更简练有效,一些冗余的代码可以剔除。一种途径就是把清单4中的代码写到一个单独的JSP页中,其他JSP页面可以通过标签 进行使用 。

十、Struts框架下的退出实现

与直接使用JSP或JSP/servlets进行Web应用开发相比,另一个更好的可选方案是使用Struts。对于一个基于Struts的Web应用来说,添加一个处理退出问题的框架可以优雅地不费气力的实现。这归功于Struts是采用MVC设计模式的,因此可以将模型和视图代码清晰的分离。另外,Java是一个面向对象的语言,支持继承,可以比JSP中的脚本更为容易地实现代码重用。对于Struts来说,清单4中的代码可以从JSP页面中移植到Action类的execute()方法中。

此外,我们还可以定义一个继承Struts Action类的Action基类,其execute()方法中包含了类似清单4中的代码。通过继承,其他Action类可以继承基本类中的通用逻辑来设置HTTP头信息以及检索HttpSession对象中的username字符串。这个Action基类是一个抽象类并定义了一个抽象方法executeAction()。所有继承自Action基类的子类都必须实现exectuteAction()方法而不是覆盖它。通过继承这一机制,所有继承自Action基类的子类都不必再担心退出代码接口。(plumbing实在不知道怎么翻译了,^+^,高手帮帮忙啊!原文:With this inheritance hierarchy in place, all of the base Action's subclasses no longer need to worry about any plumbing logout code.)。他们将只包含正常的业务逻辑代码。清单6是基类的部分代码:

清单6

publicabstractclass BaseAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {

response.setHeader( "Cache-Control" , "no-cache" );
//Forces caches to obtain a new copy of the page from the origin server
response.setHeader( "Cache-Control" , "no-store" );
//Directs caches not to store the page under any circumstance
response.setDateHeader( "Expires" , 0);
//Causes the proxy cache to see the page as "stale"
response.setHeader( "Pragma" , "no-cache" );
//HTTP 1.0 backward compatibility

if (!this.userIsLoggedIn(request)) {
ActionErrors errors = new ActionErrors();

errors.add( "error" , new ActionError( "logon.sessionEnded" ));
this.saveErrors(request, errors);

return mapping.findForward( "sessionEnded" );
}

return executeAction(mapping, form, request, response);
}

protectedabstract ActionForward executeAction(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException;

privateboolean userIsLoggedIn(HttpServletRequest request) {
if (request.getSession().getAttribute( "User" ) == null) {
return false;
}

return true;
}
}

清单6中的代码与清单4中的很相像,唯一区别是用ActionMapping findForward替代了RequestDispatcher forward。清单6中,如果在HttpSession中未找到username字符串,ActionMapping对象将找到名为sessionEnded的forward元素并跳转到对应的path。如果找到了,子类通过实现executeAction()方法,将执行他们自己的业务逻辑。因此,在struts-web.xml配置文件中为所有继承自Action基类的子类声明个一名为sessionEnded的forward元素并将其指向login.jsp是至关重要的。清单7以secure1 action阐明了这样一个声明:

清单7

<action path= "/secure1" 
type= "com.kevinhle.logoutSampleStruts.Secure1Action"
scope= "request" >
<forward name= "success" path= "/WEB-INF/jsps/secure1.jsp" />
<forward name= "sessionEnded" path= "/login.jsp" />
</action>

继承自BaseAction类的子类Secure1Action实现了executeAction()方法而不是覆盖它。Secure1Action类不需要执行任何退出代码,如清单8:

清单8

publicclass Secure1Action extends BaseAction {
public ActionForward executeAction(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {

HttpSession session = request.getSession();
return (mapping.findForward( "success" ));
}
}

上面的解决方案是如此的优雅有效,它仅仅只需要定义一个基类而不需要额外的代码工作。将通用的行为方法写成一个继承StrutsAction的基类是者的推荐的,而且这是许多Struts项目的共同经验。

十一、局限性

上述解决方案对JSP或基于Struts的Web应用都是非常简单而实用的,但它还是有某些局限。在我看来,这些局限并不是至关紧要的。

◆通过取消与浏览器后退按钮有关的缓存机制,一旦用户离开页面而没有对数据进行提交,那么页面将会丢失所有输入的数据。即使点击浏览器的后退按钮返回到刚才的页面也无济于事,因为浏览器会从服务器获取新的空白页面显示出来。一种可能的方法并不是阻止这些JSP页面包含数据数据表格。在基于JSP的解决方案当中,那些JSP页面可以删除在清单4中的代码。在基于Struts的解决方案当中,Action类需要继承自Struts的Action类而非BaseAction类。 
◆上面讲述的方法在Opera浏览器中不能工作。事实上没有适用于Opera浏览器的解决方案,因为Opera浏览器与2616 Hypertext Transfer Protocol—HTTP/1.1紧密相关。

Section 13.13 of RFC 2616 states:

User agents often have history mechanisms, such as "Back" buttons and history lists, which can be used to redisplay an entity retrieved earlier in a session.

History mechanisms and caches are different. In particular history mechanisms SHOULD NOT try to show a semantically transparent view of the current state of a resource. Rather, a history mechanism is meant to show exactly what the user saw at the time when the resource was retrieved.

幸运的是,使用微软的IE和基于Mozilla的浏览器用户多余Opera浏览器。上面讲述的解决方案对大多数用户来说还是有帮助的。另外,无论是否使用上述的解决方案,Opera浏览器仍然存在用户退出问题,就Opera来说没有任何改变。然而,正如RFC2616中所说,通过像上面一样设置头文件指令,当用户点击一个链接时,Opera浏览器不会从缓存中获取页面。

十二、结论

这篇文章讲述了处理退出问题的解决方案,尽管方案简单的令人惊讶,但在所有情况下都能有效地工作。无论是对JSP还是Struts,所要做的不过是写一段不超过50行的代码以及一个记录用户最后登陆时间的方法。在有密码保护的Web应用中使用这些方案能够确保在任何情况下用户的私人数据不致泄露,同时,也能增加用户的经验。

分享到:
评论

相关推荐

    当用户退出点击浏览器后退仍可回到原来页面的解决方案

    解决方案1:禁用缓存,前一次使用的方法,在电脑上各浏览器都没问题,但在ipad、安卓手机上仍有问题 解决方案2:禁用浏览器后退键 [removed] window.history.forward(1); 结果和方案一一样的结果,pad上没效果 ...

    JQ 页面点击后退弹出提示框

    在IT行业中,前端开发经常会遇到页面交互的问题,其中之一就是在用户点击浏览器的后退按钮时,如何优雅地处理这种行为。标题“JQ 页面点击后退弹出提示框”所涉及的知识点,就是如何使用jQuery(简称JQ)库来实现在...

    解决手机浏览器点击后退页面刷新问题,兼容苹果 safari浏览器和安卓浏览器

    解决手机浏览器点击后退页面刷新问题,兼容苹果 safari浏览器和安卓浏览器。 js的window.onbeforeunload,onunload,window.addEventListener(‘pagehide‘, () => {}手机浏览器不生效

    退出登录后点击后退问题解决方案

    ### 退出登录后点击后退问题解决方案 在Web开发中,用户登录状态的管理是非常重要的一个环节。当用户完成操作并选择退出登录时,如果直接使用浏览器的后退功能回到之前的页面,可能会出现仍然处于登录状态的情况,...

    屏蔽退格键后退网页功能

    当我们在jsp上有个只读文本框的时候,用户在文本框内点击BackSpace会后退网页,此js直接引用到jsp内就可以屏蔽退格键后退网页的功能,删除功能还在。经测试,谷歌,IE都可以用。

    解决登录注销后退失效

    在实际应用中,常常会遇到一个棘手的问题:用户在成功注销后,如果点击浏览器的“后退”按钮,仍然能够回到之前的已登录状态页面。这不仅违反了系统的安全策略,还可能导致敏感信息泄露等问题。 #### 技术原理分析 ...

    php网页后退不再出现过期

    PHP网页后退不再出现过期是指在PHP开发中遇到的一个常见问题,即在用户浏览器中点击后退按钮时,之前的网页内容重新出现的问题。这种情况通常是由于浏览器缓存机制引起的,为了解决这个问题,开发者需要采取一定的...

    解决退出后点击后退按钮仍可以登录的简单方法

    ### 解决退出后点击后退按钮仍可以登录的简单方法 在Web应用程序中,特别是那些涉及到用户认证与授权的应用程序中,确保用户安全地退出系统是至关重要的。一个常见的问题是在用户成功登出后,如果他们点击浏览器的...

    webview网页后退

    在Android开发中,WebView是一个非常重要的组件,它允许我们在应用程序中内嵌网页内容,实现与网页的交互。...通过以上方法,我们可以解决“webview后退不退出”的问题,实现用户友好且功能完善的WebView应用。

    JavaWeb页面中防止点击Backspace网页后退情况

    为了解决这一问题,开发者可以采取措施来阻止Backspace键触发页面后退。本文将详细介绍如何在JavaScript中实现这一功能,同时确保不影响密码输入框、单行文本输入框和多行文本输入框的正常回退操作。 首先,我们...

    jQuery实现页面点击后退弹出提示框的方法

    在网页开发中,有时我们需要在用户点击浏览器的后退按钮时执行特定的操作,例如弹出一个提示框。jQuery 提供了一种方式来监听并处理这种行为。本篇将详细介绍如何利用 jQuery 实现这一功能,以及涉及到的事件触发...

    解决Vue 浏览器后退无法触发beforeRouteLeave的问题

    总之,解决Vue浏览器后退无法触发`beforeRouteLeave`的问题需要对Vue Router的导航机制有深入理解。上述提供的解决方案是一种临时对策,但最佳实践是优化路由设计,以确保在所有情况下都能正确执行必要的逻辑。同时...

    解决微信授权成功后点击按返回键出现空白页和报错的问题

    微信授权我是 在index.vue做的授权,是一个空白页,因为授权需要回调所以这个页面会刷新两次,当我们授权成功进入主页面后,点击返回键或者点击手机的物理返回键,因为浏览器history机制,按物理返回或者返回肯定是...

    防止刷新后退重复提交

    在Web开发中,用户在提交表单后可能会意外地点击浏览器的刷新或后退按钮,导致数据重复提交,这在数据库操作中可能引起严重问题,比如财务交易的重复扣款或者用户信息的重复录入。针对这个问题,我们可以采取多种...

    屏蔽浏览器的后退按钮

    为了解决这个问题,开发者可能会考虑屏蔽浏览器的后退按钮。 #### 可行性分析 **重要提示:** 直接屏蔽浏览器的后退按钮并不是一个推荐的做法,因为这会影响到用户体验和浏览器的基本功能。此外,大部分现代浏览器...

    QWebEngineView使用,点击链接,上一页,响应网页消息等

    本文将详细解析如何使用`QWebEngineView`实现点击链接、上一页功能,以及如何响应网页消息,并针对其潜在的内存问题进行讨论。 1. **创建QWebEngineView** 创建一个`QWebEngineView`实例非常简单,通常在窗口或...

    iOS新版微信底部工具栏遮挡问题完美解决

    了解了该问题出现的原因,我们也就有了解决办法。首先想到的方案就是控制浏览器的历史记录。由于考虑到安全性问题,浏览器的历史记录不支持删除和修改等操作,只能通过新增或替换的方式来实现对浏览历史的操作,因此...

    在vue中阻止浏览器后退的实例

    然而,在使用SPA时,一个常见的问题是如何处理浏览器的后退按钮。在传统的多页面应用(MPA)中,用户可以自由地在各个页面之间前进和后退。但在SPA中,由于只有一个页面,所以管理历史记录的方式略有不同。 首先,...

Global site tag (gtag.js) - Google Analytics