踩的一個小坑——JavaScript刷新頁面



   本篇文章緣由是來自於前幾天的一個線上問題,這個線上問題大概是這樣:有個頁面上會定時用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對象屬於瀏覽器對象中的一員,它可以通過windowlocation屬性來訪問,其屬性與功能都是與URL及其操作相關的。

首先是利用Location的三個對象方法實現頁面刷新:

1.location.assign(location.href)(參數可以填入任何可以表示本頁URL的字符串)

其原本的作用是加載一個新的文檔,也就是跳轉到一個新的頁面,通過參數中引入本頁的URL,使得瀏覽器會重新加載本文檔,也就是實現了刷新頁面的效果。

這種刷新的效果類似於用戶在地址欄中重新輸入了本頁的地址後回車訪問的效果,所以POST表單的內容不會出現被重複提交的情況,而是會轉變成一個對當前URLGET請求。刷新後的效果如下:

    

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的各個屬性(hashhosthostnamehrefpathnameportprotocolsearch)都可以觸發這種刷新,更爲喪病的做法是直接採用location=location的方式來觸發這種刷新。


 

         2.History對象的操作

History對象也是瀏覽器對象的一員,顧名思義就是瀏覽歷史記錄所對應的的一個可操作的對象,通過利用其屬性和方法可以查看和操作瀏覽器歷史記錄,其back()forward()就類似於用戶點按前進按鈕和後退按鈕時的操作,而go()操作則用於指定加載一個歷史記錄裏的頁面,這裏就要利用到go()方法的一個特性,刷新頁面的代碼如下:

history.go(0);

也就是給go()方法傳一個0,這相當於告訴瀏覽器我想加載歷史記錄裏的當前頁面,這又等於變相實現了刷新當前頁面的效果。

值得注意的是瀏覽器本身在前進後退時也會觸發沒有提示的POST數據重複提交,所以通過history對象來實現刷新當前頁面的時也會導致POST表單的重複提交。通過這種方式刷新後的效果如下:

3.其他一些雜項的有瀏覽器限制的方法

document.execCommand('Refresh')

documentexecCommand方法一般用於控制一些可編輯的iframe內容,有些HTML5的富文本編輯器會基於這個方法去實現,但是事實上這個方法並不屬於標準方法,其支持內容各個瀏覽器各不相同。各個瀏覽器的支持程度可以參見http://w3help.org/zh-cn/causes/BX9054

在刷新當前頁面這個命令的支持上,非常坑爹的只有IE系列現在支持了這個命令,其效果是真正意義上的等同於用戶按下F5POST數據的重複提交的提示框也會原封不動地彈出,效果如下:


window.navigate(location)

這個就是真正意義上的IEonly的用法了,只有在MSDN上有對應的說明,而在標準的window對象中根本就沒有這個方法,所以也就只能在IE下使用了。

這個navigate()方法與location.assign()類似,也不會出現POST數據重複提交的情況,其效果如下:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章