您的位置:首页 > Web前端 > JavaScript

踩的一个小坑——JavaScript刷新页面

2015-06-05 13:08 477 查看


本篇文章缘由是来自于前几天的一个线上问题,这个线上问题大概是这样:有个页面上会定时用Ajax调用一个接口,并对页面作出一些调整,当满足某个条件时会将页面整个刷新,而这个页面上有一个文件上传的表单,它是对本页地址直接进行POST提交的,使得刷新页面时会出现重复提交的情况,于是也就产生了这个线上问题。在这个线上问题中牵涉到了两个问题,这也就是本文所想要讨论的问题:JavaScript如何去刷新页面,以及刷新页面后会不会造成POST数据的重复提交。

为了测试各个JavaScript刷新页面的方式是否会造成POST数据的重复提交,本文引入了一个简单的测试页面,测试页面的地址位于:http://jp01.sanaecon.com/refresh.php,该页面简单的提供了一个本页的POST
Form表单,并直接将$_POST对象var_dump显示出来,这样就可以直观地看到当前页面是处于表单提交的POST请求的状态还是停留在显示页面的GET请求的状态。

GET请求的状态时的截图:



点击Submit后的POST请求时的截图:



通过对已经提交过POST的页面调用刷新的命令,便可以根据结果来判断这种刷新的方式会不会导致POST数据的重复提交,顺带一提该页直接点击刷新按钮时浏览器会直接提示你POST数据会重新发送。



JavaScript刷新页面的方式有许多种,大致可以总结如下:
1.对Location对象的操作

最常见的使用JavaScript刷新页面的方式都是通过对Location对象的操作来实现对页面的刷新的,Location对象属于浏览器对象中的一员,它可以通过window的location属性来访问,其属性与功能都是与URL及其操作相关的。

首先是利用Location的三个对象方法实现页面刷新:
1.location.assign(location.href)(参数可以填入任何可以表示本页URL的字符串)

其原本的作用是加载一个新的文档,也就是跳转到一个新的页面,通过参数中引入本页的URL,使得浏览器会重新加载本文档,也就是实现了刷新页面的效果。

这种刷新的效果类似于用户在地址栏中重新输入了本页的地址后回车访问的效果,所以POST表单的内容不会出现被重复提交的情况,而是会转变成一个对当前URL的GET请求。刷新后的效果如下:



2.location.reload()、location.reload(true)

该对象方法是属于直接语义上就对应着重新载入的方法,其效果也是如其名所示,其等同于用户点按F5或者点击刷新按钮的效果,该方法可以接受一个布尔值的参数,这个参数决定了这次reload()是否是强制刷新,如果强制刷新的话浏览器的缓存将会被绕过而强制从服务器重新加载这个页面,这时就相当于用户点按Ctrl+F5的效果了。

需要注意的是POST页面虽然用户点按刷新的时候会像之前截图里那样跳出个确认窗口提示用户表单会被再次提交,但是使用Chrome浏览器时调用这个方法时则根本不会跳出这种确认窗口,直接默认再次提交表单,这也就是导致之前线上问题的罪魁祸首。而IE浏览器则与正常刷新时一样会弹出提示,其他浏览器暂未测试。通过这种方式刷新后的效果如下:



3.location.replace(location.href)(参数可以填入任何可以表示本页URL的字符串)

语义上来说是直接用一个新文档来取代当前文档,同样通过通过参数中引入本页的URL,使得浏览器会重新加载本文档,replace方法与assign方法不同之处在于其是直接替换本文档而不是去访问一个新文档,所以在浏览器的历史记录中不会出现一次访问而是直接替代本次访问,但是由于这里实现的刷新当前页面的效果,在这种情况下replace方法和assign方法的表现是相同的。

在POST表单提交上,replace也和assign一样,并不会导致POST表单的重复提交。通过这种方式刷新后的效果如下:



其他的不正经的利用location的刷新页面方法:

location.href=location.href(等等一系列对location的可读可写的属性的复写)

这些方法都是利用Location的属性的可写的特点,当这些属性被写时就相当于浏览器地址栏的内容被变更后回车访问变更后的URL,其效果就类似于assign方法,而通过赋给自己当前值的方式可以触发一次属性写但是不改变属性的值,从而变相实现了刷新当前页面。

由于和assign类似,这种方式也不会触发POST的重新提交,location的各个属性(hash、host、hostname、href、pathname、port、protocol、search)都可以触发这种刷新,更为丧病的做法是直接采用location=location的方式来触发这种刷新。



2.对History对象的操作

History对象也是浏览器对象的一员,顾名思义就是浏览历史记录所对应的的一个可操作的对象,通过利用其属性和方法可以查看和操作浏览器历史记录,其back(),forward()就类似于用户点按前进按钮和后退按钮时的操作,而go()操作则用于指定加载一个历史记录里的页面,这里就要利用到go()方法的一个特性,刷新页面的代码如下:

history.go(0);

也就是给go()方法传一个0,这相当于告诉浏览器我想加载历史记录里的当前页面,这又等于变相实现了刷新当前页面的效果。

值得注意的是浏览器本身在前进后退时也会触发没有提示的POST数据重复提交,所以通过history对象来实现刷新当前页面的时也会导致POST表单的重复提交。通过这种方式刷新后的效果如下:



3.其他一些杂项的有浏览器限制的方法

document.execCommand('Refresh')

document的execCommand方法一般用于控制一些可编辑的iframe内容,有些HTML5的富文本编辑器会基于这个方法去实现,但是事实上这个方法并不属于标准方法,其支持内容各个浏览器各不相同。各个浏览器的支持程度可以参见http://w3help.org/zh-cn/causes/BX9054

在刷新当前页面这个命令的支持上,非常坑爹的只有IE系列现在支持了这个命令,其效果是真正意义上的等同于用户按下F5,POST数据的重复提交的提示框也会原封不动地弹出,效果如下:



window.navigate(location)

这个就是真正意义上的IEonly的用法了,只有在MSDN上有对应的说明,而在标准的window对象中根本就没有这个方法,所以也就只能在IE下使用了。

这个navigate()方法与location.assign()类似,也不会出现POST数据重复提交的情况,其效果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: