文章來自:mp.weixin.qq.com/s/Qp0y_KXjSSbCCBB...
最近發現了一個ajax
非同步請求的問題,用$.post
、$.get
、$.ajax
請求PHP伺服器時,總是無法非同步返回資料。
經多次測試才發現:
– 不同瀏覽器,請求不同域名-不阻塞:無需實驗
– 不同瀏覽器,請求同域名-不阻塞:session_id()
返回不同
– 同一瀏覽器,請求不同域名-不阻塞:session_id
返回不同
– 同一瀏覽器,請求同域名-阻塞:session_id()
返回相同
發現問題所在:
1 關閉XDEBUG
2 SESSION
鎖
3 清除輸出緩衝區
1 關閉XDEBUG
XDEBUG
是實時除錯。除錯時,它將保持FPM
以確保執行緒正在工作以避免資料汙染。
典型的測試方法是,使用XDEBUG
進行除錯時,開啟另一個瀏覽器並訪問該站點,該站點這個時候是無法訪問的。
這對並行響應有重大影響,即,即使前端傳送多個請求,它也受XDEBUG
控制,並且只能同時響應一個。
另外,由於XDEBUG
依賴於SESSION
,因此即使您使用session_write_close()
,也要關閉會話鎖(請參見下文)。XDEBUG
仍會自動開啟。
2 SESSION
鎖
用 session_write_close()
關閉SESSION
的寫鎖,這適合SESSION
儲存為File
的情況。如果SESSION
儲存在Redis
,則不需要。
3 清除輸出緩衝區
使用session_write_close()
可能無法立即關閉SESSION
鎖,所以在這個方法之前加上:ob_end_flush()
。讓 session_write_close()
馬上生效。
4 示例
有如下一個範例,當點選【提交】按鈕時,前端會給後臺伺服器傳送兩種請求。
一種是get
請求,每隔1秒請求一次。
一種是post
請求,最開始的時候傳送一次,然後等待相應結束。
看看HTML程式碼
<form>
<input type="submit" value="提交" />
</form>
<script src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript">
$('form').on('submit', function(e) {
e.preventDefault();
// 每隔一秒請求一次伺服器
var id = setInterval(function() {
$.get(
'save.php?action=get',
{},
function(data) {
console.log(data);
},
'json'
);
}, 1000);
$.post(
'save.php?action=post',
{},
function(data) {
console.log(data);
// 停止定時迴圈
clearInterval(id);
},
'json'
);
});
</script>
php程式碼
<?php
session_start();
$action = $_GET['action'];
if ($action == 'post') {
$_SESSION['time'] = 0;
session_write_close();
while ($_SESSION['time'] < 5) {
session_start();
$_SESSION['time'] = $_SESSION['time'] + 1;
// 將SESSION資料寫入檔案中,並關閉寫鎖
session_write_close();
// sleep()模擬花費時間較長的程式,這樣在關閉寫鎖之後,
// 伺服器就能夠相應別的請求,如下的$action=get,
sleep(1);
}
echo json_encode([session_id() => $_SESSION['time']]);
exit();
}
if ($action == 'get') {
echo json_encode([session_id() => $_SESSION['time']]);
exit();
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結