Javascript 获取请求之间的竞争
我正在开发一个跟踪器,它应该在我们客户的网站上收集一些数据,并在网站用户离开页面时使用fetch请求将数据发送给我们的api 其想法是使用事件处理程序发送请求,但我已经读到,为了涵盖大多数浏览器,我还需要使用事件处理程序 这是我们的客户将在其网站上发布的跟踪器代码的相关部分:Javascript 获取请求之间的竞争,javascript,php,ajax,api,fetch,Javascript,Php,Ajax,Api,Fetch,我正在开发一个跟踪器,它应该在我们客户的网站上收集一些数据,并在网站用户离开页面时使用fetch请求将数据发送给我们的api 其想法是使用事件处理程序发送请求,但我已经读到,为了涵盖大多数浏览器,我还需要使用事件处理程序 这是我们的客户将在其网站上发布的跟踪器代码的相关部分: var requestSent = false; function submitData(element_id, url) { if (!requestSent) { v
var requestSent = false;
function submitData(element_id, url) {
if (!requestSent) {
var data = JSON.stringify({ourobject});
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type':'application/x-www-form-urlencoded',
},
body: data,})
.then(response => response.json())
.then((data) => {
console.log('Hello?');
requestSent = true;
});
}
}
window.addEventListener('beforeunload', function (e) { submitData(1, "https://oursiteurl/metrics");});
window.addEventListener('unload', function(event) {submitData(1, "https://oursiteurl/metrics"); });
我在chrome上对此进行了测试,两个请求都通过了,而不仅仅是第一个成功的请求,这会导致数据库中出现重复数据
在将控制台日志放在requestSent标志设置为true的部分旁边之后,我意识到部分代码永远不会执行
如果我在“网络”选项卡中保留日志,它会说两个请求都被取消,即使数据到达我们的端点
我们的api是在Codeigniter中创建的,下面是/metrics端点
public function submit () {
$this->cors();
$response = [
'status' => 'error',
'message' => 'No data',
];
$data = json_decode(file_get_contents('php://input'), true);
if (empty($data)) {
echo json_encode($response);exit();
}
// process data and do other stuff ...
Cors功能:
private function cors() {
// Allow from any origin
if (isset($_SERVER['HTTP_ORIGIN'])) {
// Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
// you want to allow, and if so:
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
// may also be using PUT, PATCH, HEAD etc
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
}
}
编辑:
由于@CBroe建议使用,使用它消除了卸载和beforeuload事件处理程序的需要:
submitData现在看起来如下所示:
...
if (navigator.sendBeacon) {
let beacon = navigator.sendBeacon(url, data);
console.log( 'Beacon', beacon );
} else { // fallback for older browsers
if (!requestSent) {
console.log( 'Data object from fallback', data );
var xhr = new XMLHttpRequest();
xhr.open("POST", url, false); // third parameter of `false` means synchronous
xhr.send(data);
}
...
这样做只允许我保留beforeunload事件处理程序,因为它在ie和chrome上都可以工作:
window.addEventListener('beforeunload', function (e) { submitData(1, "https://oursiteurl/metrics");});
想法是使用beforeunload
事件处理程序发送请求,但我在这里读到,为了覆盖大多数浏览器,我还需要使用unload
事件处理程序
这两种方法都不太适合发出AJAX/fetch请求,它们很可能在页面实际卸载时被取消
您更应该使用,这是专门为此类跟踪/保持活动状态请求而设计的
根据MDN上的浏览器兼容性列表,Internet Explorer还不支持它。如果您也需要跟踪,那么可以采用双管齐下的方法—针对支持它的浏览器的Beacon,针对IE的AJAX/fetch回退。您应该使用什么而不是AJAX或fetch(如果你可以解决IE支持不足的问题。如果你不能解决,那么我仍然会在支持它的浏览器中使用它,并可能实现AJAX/fetch作为IE的后备方案。)@CBroe感谢您的建议,我将为支持它的浏览器切换到beacon api,但我需要它在尽可能多的浏览器上工作,所以我仍然需要使用它作为备份。@CBroe您的建议基本上解决了我的问题,我已经编辑了我的问题如果您对我的解决方案感兴趣,如果您将其作为答案发布,我将接受吧,谢谢!