首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >获取请求之间的争用

获取请求之间的争用
EN

Stack Overflow用户
提问于 2020-06-25 14:17:10
回答 1查看 100关注 0票数 0

我正在开发一个跟踪器,它应该收集客户端网站上的一些数据,并在站点用户离开页面时使用fetch请求将其发送到api。

我的想法是使用卸载前事件处理程序发送请求,但是我读过这里,为了覆盖大多数浏览器,我还需要使用卸载事件处理程序。

这是我们的客户将在其网站上添加的跟踪器代码的相关部分:

代码语言:javascript
复制
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端点

代码语言:javascript
复制
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功能:

代码语言:javascript
复制
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建议使用信标API,使用它消除了卸载和卸载前事件处理程序的需求:

submitData现在看起来如下所示:

代码语言:javascript
复制
...
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);
    }
 ... 

这样做只允许在卸载事件处理程序之前保持不变,因为它同时工作在ie和chrome上:

代码语言:javascript
复制
 window.addEventListener('beforeunload', function (e) { submitData(1, "https://oursiteurl/metrics");});
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-26 06:27:35

我们的想法是使用beforeunload事件处理程序发送请求,但是我在这里看到,为了覆盖大多数浏览器,我还需要使用unload事件处理程序。

两者都不太适合发出AJAX/fetch请求,当页面实际卸载时,它们可能会被取消。

您应该使用信标API,它专门为这类跟踪/保持活动请求而设。

但是,根据MDN上的browser compability列表,Internet还不支持它。如果您也需要跟踪,那么可以采用双管齐下的方法--支持它的浏览器为信标,为IE提供AJAX/fetch备份。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62577488

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档