15

我有以下代码使用 sendBeacon 方法发送异步 HTTP 请求,

var data = {
 name: 'test',
 uniqueId: Math.random()
};
var blob = new Blob([JSON.stringify(data)], {type : 'application/json'});
navigator.sendBeacon('http://example.in/data/post', blob);

这段代码已经运行了很长时间。目前,由于 chrome https://bugs.chromium.org/p/chromium/issues/detail?id=490015中的安全问题,我们看到错误“无法在 'Navigator' 上执行 'sendBeacon': sendBeacon()实验上不允许类型不是 CORS-safelists MIME-type 的 Blob。有关详细信息,请参阅http://crbug.com/490015

是否有任何解决方法可以通过使用相同的 sendBeacon API 修改请求标头来发送 JSON 数据,直到问题得到解决?这对于依赖此 API 的站点将很有用,可以继续使用直到修复完成。关于使用 XHR 发布数据的建议没有用。

4

3 回答 3

21

现在 sendBeacon 中 Content-Type 标头的唯一允许值是:

  • 应用程序/x-www-form-urlencoded
  • 多部分/表单数据
  • 文本/纯文本

我在我们的项目中遇到了类似的问题,我最终将数据作为“文本/纯文本”发送;charset=UTF-8' 并在服务器端读取 json 内容的流。

客户:

const blob = new Blob([JSON.stringify(myData)], { type: 'text/plain; charset=UTF-8' });
navigator.sendBeacon(appData.ReleaseSessionUrl, blob);

服务器:

using (var reader = new StreamReader(this.Request.InputStream))
{
   var jsonData = reader.ReadToEnd();
   var sessionData = JsonConvert.DeserializeObject<MyDataType>(jsonData);
}

不确定这是否对您有帮助。

https://github.com/GoogleCloudPlatform/stackdriver-errors-js/issues/10

于 2017-08-10T20:23:25.240 回答
2

请注意,该方法似乎在大多数浏览器上都被破坏了。这是关于该主题的大型数据研究。

于 2019-12-17T12:33:14.377 回答
0

简短回答:截至 2021 年,该问题已得到。

长答案(背景):我在从事timeonsite JS开发时打开了这个问题。它曾经在 Chrome、Firefox 和许多其他浏览器中运行良好。但是,几个月后,我突然遇到了CORS 安全列表错误,并且无法实时节省站点数据的时间。它迫使我们回退到 Localstorage,这将在每个用户会话中导致(N-1)次网页浏览和随后丢失的现场时间数据,这是一个关键的网络分析指标。我们一直在热切地等待浏览器供应商解决这个问题。这是我们用于捕获实时的配置,它直接依赖于sendBeacon() API

<script type="text/javascript">
    var Tos;
    (function(d, s, id, file) {
        var js, fjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) return;
        js = d.createElement(s);
        js.id = id;
        js.onload = function() {
            // save with XMLHttpRequest (sync=true is blocking approach) or sendBeacon(preferred approach)
            var config = {
                trackBy: 'seconds',
                callback: function(data) {
                    console.log(data);

                    // give your endpoint URL/ server-side URL that is going to handle your TOS data which is of POST method. Eg. PHP, nodejs or python URL which saves this data to your DB
                    var endPointUrl = 'http://localhost:4500/tos'; // replace with your endpoint URL

                    if (data && data.trackingType) {
                        if (data.trackingType == 'tos') {
                            if (Tos.verifyData(data) != 'valid') {
                                console.log('Data abolished!');
                                return; 
                            }
                        }
                        
                        // make use of sendBeacon if this API is supported by your browser.
                        if (navigator && typeof navigator.sendBeacon === 'function') {
                            data.trasferredWith = 'sendBeacon';
                            var blob = new Blob([JSON.stringify(data)], {type : 'application/json'});
                            navigator.sendBeacon(endPointUrl, blob);
                        }

                        /*else {

                            // XMLHttpRequest begins..
                            // XMLHttpRequest with sync=true (blocking approach)
                            // XMLHttpRequest code block here to post your data
                        }*/
                    }
                }
            };

            if (TimeOnSiteTracker) {
                Tos = new TimeOnSiteTracker(config);
            }
        };
        js.src = file;fjs.parentNode.insertBefore(js, fjs);
    } (document, 'script', 'TimeOnSiteTracker', 'https://cdnjs.cloudflare.com/ajax/libs/timeonsite/1.1.0/timeonsitetracker.min.js'));
</script> 

正如您在上面看到的,由于 CORS 安全列表问题,过去几年我们一直在注释掉 sendBeacon() 代码块,并依赖带有async=false的XMLHTTPRequest来发布数据,这种方法在许多浏览器(尤其是在移动设备上)是阻塞方法并且不太可靠设备。

最近,浏览器供应商似乎已经解决了这个问题,并且sendBeacon() API又回来了。我在许多浏览器上进行了测试,它似乎工作正常。因此,截至 2021 年,此问题被标记为“已解决”。我希望您添加适用于beforeunload / unload窗口事件的版本/年份的设备/浏览器。

于 2021-11-23T06:17:22.537 回答