最近做了個項目,其中有項目需求是這樣的,點擊一個文件鏈接下載該文件,同時向後台發送請求,在開發過程中問題百出,小編把問題總結分享在腳本之家平台,供大家參考
需求很簡單,點擊一個文件鏈接下載該文件,同時向後台發送請求。需求很常見,使用者點擊下載後通常要進行下載量的統計,統計的話可以利用script標籤或img標籤(圖片ping) 的跨域能力,將它們的src 屬性指向統計地址,但是這次用了ajax 進行統計,遂出現了這個問題。
demo 程式碼如下:
<a id="a" href="http://c758482.r82.cf2.rackcdn.com/Sublime Text 2.0.2 x64 Setup.exe" >click</a> <script src="jQuery.js"></script> <script> document.getElementById("a").onclick = function(e) { $.post("data.php"); }; </script>
我們都知道,如果一個a 標籤同時擁有onclick 事件和href 屬性,onclick 事件的回呼會在預設事件(即跳轉)之前執行,這也正是可以在onclick 事件中用類似e.preventDefault() 的程式碼去除預設事件(即跳轉)的原因。所以以上程式碼,如果點擊 a 標籤,首先會執行 onclick 事件的回調,即發送 ajax 請求,理論上,因為代碼中的 ajax 是異步的(其實同步也一樣),所以會一邊請求一邊打開下載文件。
chrome、UC、opera、2345瀏覽器中表現均和預期一致,firefox 下點擊能跳出下載文件,但是 ajax 部分報錯,IE 下未測試。
一開始的錯誤想法是,跨域導致報錯。當點擊下載連結時,ajax 請求會以為頁面即將跳到 href 所指的地址,導致瀏覽器為該 ajax 跨域。這個錯誤想法很快就被推翻,一是因為先進行ajax 請求,所以請求瞬間並未跨域;二是並未報跨域錯誤(通常如果是跨域錯誤控制台會指出);三是如下代碼更進一步證明了該錯誤。
<a id="a" href="http://c758482.r82.cf2.rackcdn.com/Sublime Text 2.0.2 x64 Setup.exe" >click</a> <script src="jQuery.js"></script> <script> $.post("data.php"); // data.php sleep(100) </script>
開啟該頁面,隨即進行 ajax 請求,一旦點擊了下載按鈕,請求即被中止。如果a 標籤的href 屬性值不是檔案位址,而是用任意的一個url 替換,如果點擊a 標籤,頁面會立即跳到該標籤所指向的位址,頁面都不存在了,ajax 自然也中斷了。如果 a 標籤指向的是檔案位址,在 ff 下方是不是也會被一樣地解析呢(瀏覽器以為要跳到該位址了,而將 ajax 中止)?
答案是肯定的,我在 stackoverflow 中找到了答案。
When clicking the download link you are leaving the page, even it does not look so. If there would no file transfer, you would see the requested page.. try to set a target="_blank" or use_blank" or use an iframe as target for the link.
從提問可以看出,2010 年時chrome 和ff 都有類似的問題,而chrome 或者說是webkit 內核的瀏覽器在之後的版本迭代中修復了這個問題, ff 則一直將問題留到了現在(個人認為這不太合理)。
知道了問題的根源,解決方案也就呼之欲出了。
方法一:
最簡單的方法無非是給a 標籤加上target="_blank",事實上,通常網頁都是這麼做的,這也是值得肯定的做法。
方法二:
既然 a 標籤的預設行為會使得 ajax 請求中斷,那麼將 "預設行為" 放在請求之前呢?
<a id="a" href="javascript:;" >click</a> <script src="jQuery.js"></script> <script> document.getElementById("a").onclick = function(e) { location.href = "http://c758482.r82.cf2.rackcdn.com/Sublime Text 2.0.2 x64 Setup.exe"; $.post("data.php"); }; </script>
方法三:
設定計時器使請求延遲,但因為a 標籤的預設跳轉不屬於Javascript 執行緒能控制的範圍,所以這個延遲閾值的設定非常重要,我本地測試結果居然是2ms(也是萬萬沒想到),一般設定為100ms 左右就ok 了。這個方法不優雅,不應該使用 。
<a id="a" href="http://c758482.r82.cf2.rackcdn.com/Sublime Text 2.0.2 x64 Setup.exe" >click</a> <script src="jQuery.js"></script> <script> document.getElementById("a").onclick = function(e) { setTimeout(function() { $.post("data.php"); }, 100); }; </script>
上面是我整理給大家的,希望未來會對大家有幫助。
相關文章:
細數Ajax請求中的async:false和async:true的差異
#以上是Ajax請求過程中下載檔案在FireFox(火狐)瀏覽器下的相容問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!