PHP的session阻塞機制帶來的單頁面多ajax請求阻塞的解決
遇到一個有意思的問題:
比如在一個頁面中,有兩個不同的ajax請求,分別在兩個函式中呼叫去請求,前一個ajax是長輪詢的請求。後一個ajax是每隔幾秒執行一次,負責讀取前一個ajax執行的日誌,並把讀到的日誌內容顯示在當前頁面的某一個div中。
問題很簡單,但意外發生了。
前面的ajax請求開始執行後,日誌內容也正常不斷的生成。但後一個ajax定時去取日誌卻總也取不到,看到的現象是沒反應。直到第一個ajax請求執行結束,日誌內容才一下子全部被讀出,顯示在div中,這顯示不是想要的結果,想要的是在第一個ajax請求在執行過程中,就拿到執行日誌並顯示。
這個奇怪了,怎麼會取不到呢?註釋掉第二個方法中的Ajax的請求程式碼,直接寫死一句話,然後重新整理後再執行前一個Ajax請求後,觀察到第二個註釋後ajax請求後的函式正常工作,寫死的的那句話也每幾秒一次寫入到結果div中。說明定時執行是正常工作的,但如果有Ajax請求就無法正常工作,那問題到底出在哪裡?
開啟firebug,觀察發現,當前一個ajax請求在進行時,後面的定時請求也在不斷生成,但是一直是等待狀態,非要等到前一個ajax請求執行結束,後面的ajax請求才能成功請求!說明前一個ajax執行導致了阻塞影響到了後面的所有請求!
查閱相關PHP阻塞的資料,發現有人遇到過類似問題,是由於php的session阻塞機制導致的!
只要執行了session_start方法,就會建立session,我們知道,每個客戶端在請求的時候,session是儲存在檔案中的。而且同一個客戶端只會共用一個相同的session。一個請求佔有了Session後,實際上是以讀寫方式打開了session檔案。為了防止衝突,後面的請求只能等待。
在本例中,第一個長時間執行的ajax佔有了session後,加了讀寫鎖,後面的請求無法獲得相同session檔案的讀寫鎖,故只能等待前一個請求釋放session。
搞清楚了問題原因,解決就好解決了。
1)如果可以不用session_start,則不使用。有時候執行這個句往往是出於習慣或原來程式碼就這麼寫的,為什麼不知道,呵呵。
2)無法避免使用session_start的,那也沒關係,寫完session內容後,及時關閉。關閉方法很簡單。
session_write_close();
本例是第二種情況,這兩個ajax請求都不需要讀寫session,於是執行在最前面加上了session_write_close();後問題解決。