分享今天卡到陰,耗掉我半小時青春的鬼問題。

有個待辦事項清單網頁,使用者可點選待辦項目以 Modal Dialog 連上位於其他主機的網頁執行作業,待 Modal Dialog 關閉,待辦清單需依據執行結果決定是否將該筆作業註記為已完成,避免重複處理。由於待辦清單與執行作業網站分處不同伺服器,跨站台情境無法使用 returnValue 傳回結果,故我會靠另設狀態程式從中傳話以克服限制。(細節可參考 TIPS-跨Domain傳遞Modal Dialog結果

情境示意如下:

//開啟另一台主機的網頁處理資料
var url = "httq://serverB/edit?id=" + item.Id;
//在url後方加上callback以更新狀態
var fixedUrl = url + "&xss_cb=" + encodeURIComponent("http://serverA/update_state?id=" + item.Id);
//使用Modal Dialog模式開啟serverB上的網頁,若作業成功呼叫xss_cbo傳入的serverA網址更新狀態
window.showModalDialog(fixedUrl, window);
//Modal Dialog關閉後檢查狀態是否更新已完成
$.get("check_state?id=" + item.Id ).done((res) => {
	if (res == "OK")  {
		//將該筆資料註記為已完成
	}
});

同事報案,這段狀態更新機制怪怪的,有時執行動作卻沒註記完成,有時則明明沒執行,只是關閉視窗項目就被標為完成,歸納不出什麼規則。

將測試拉回我的主機進行分析,在 JavaScript 加入 alert() / console.log() 試了一陣子,結果依然好時壞,動用 F12 開發者工具跟 Fidller,依然沒頭緒。

不久後,我發現一個現象,每當開啟 IE F12 開發者工具設了中斷點偵錯,程式就運作正常,關閉 F12 Bug 就開始作怪,再開啟 F12 想一探究竟又消失,這 Bug 彷彿有靈性似的... Orz

鬼打牆近十分鐘,從 Fiddler 再找到一條線索 - 關閉 F12 出問題時,Fiddler 不會出現 $.get("check_state?id=…") 封包! 但由 console.log() 軌跡則顯示 $.get() 有被執行。

啊! 是 Cache!!!

我也瞬間明白,為什麼一開 F12 時網頁就正常。答案就在下圖中,我的 $.get() 網址忘了加入亂數,因網址相同有可能會讀到先前 Cache 的內容;開啟 F12 時,因啟用了「一律從伺服器重新整理」,排除被 Cache 誤導的可能,網頁就正常了。

問題在將 "check_state?id=" + item.Id 改成 "check_state?id=" + item.Id + "&_=" + (new Date().getTime()) 後修復,而我,花 30 分鐘上了一課,遇到「一開啟 F12 問題就消失」的情境,請優先檢查是否與 Cache 行為有關。(註:Chrome F12 也有 Disable Cache 選項,類似現象也可能上演)

註: 關於加參數避免 Cache 的寫法,除了自己在 URL 加上亂數或 Timestamp(亂數仍存在極低的重複機率,一般循序執行下時間值無重複風險,是更好的選擇),還可改寫成 $.ajax({ url: "check_state", data: { id: item.Id }, cache: false}) 由 jQuery 加上 Timestamp 避免讀取 Cache。(感謝大家留言提醒) 參考: jQuery.ajax() - jQuery API Documentation邊做邊學jQuery系列14 - 呼叫總部-jQuery.ajax()

Useful hint for debugging with browser F12 dev tools. The F12 tools provide "always refresh from server" feature may change the cache behavior, please consider it to avoid from confusion.


Comments

# by 路過

Jquery的$.ajax()其中有一個屬性是cache可以設成false https://api.jquery.com/jQuery.ajax/

# by Jeffrey

to 路過,感謝提醒,已補充本文。

Post a comment