sendBeacon API not working temporarily due to security issue, any workaround?
Asked Answered
G

3

18

I have the following code to send asynchronous HTTP request using sendBeacon method,

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);

This code has worked fine for a long time. Currently, due to security issues in chrome https://bugs.chromium.org/p/chromium/issues/detail?id=490015, we see the error "Failed to execute 'sendBeacon' on 'Navigator': sendBeacon() with a Blob whose type is not CORS-safelists MIME-type is disallowed experimentally. See http://crbug.com/490015 for details."

Is there any workaround to send JSON data by modifying request headers using the same sendBeacon API till the issue is fixed? It'll be useful for sites depending on this API to continue to use till a fix is made. Suggestions on using XHR to post data are not useful.

Gulfweed answered 24/7, 2017 at 6:34 Comment(3)
This issue has been resolved by browser vendors. See my answer below along with issue background.Gulfweed
Nice post & answer. How do you monitor for errors? It could be that in the future sendBeacon() do not work well again for XXX reasons.Kyanize
As far as monitoring errors, one general approach (something feasible) is to persist the browser terminal logs in any browser. It is likely give you some ideas about issues with the API call at browser level with (ping) types and not usual XHR category. As far as its downfall in future, I'm greatly worried. We'll going backwards. It'll likely break many potential use-cases associated with unload events for numerous web applications if this API is not consistently supported in future.Gulfweed
G
3

Short Answer: The issue has been resolved as of 2021.

Long Answer(background): I opened this issue some time back when I worked on timeonsite JS development. It used to work well in Chrome, Firefox & many other browsers. But, after few months, suddenly I got above CORS safelist error and failed to save time on site data real-time. It forced us to fallback on Localstorage which will result in (N-1) pageviews & subsequently lossy time-on-site data, a crucial web analytics metric, during each user session. And we have been eagerly waiting for this issue to be resolved from browser vendors. This is the configuration we used for capturing real-time that depends directly on 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> 

As you saw above, we have been commenting out sendBeacon() code block for last few years due to the CORS safelist issue and depended on XMLHTTPRequest with async=false to post data which is blocking approach and not quite reliable on many browsers especially on mobile devices.

Recently, it seems the issue has been resolved by browser vendors and sendBeacon() API is back for consumption. I tested across a number of browsers and it seems working fine. So, this issue is marked as "resolved" as of 2021. I would like you to add the devices/browsers that work well with version/year favorably mentioned for beforeunload/unload window events.

Gulfweed answered 23/11, 2021 at 6:17 Comment(2)
Chrome: version-95.0.4638.69, (2021) workingGulfweed
Firefox: version-94.0.1 (2021) workingGulfweed
C
22

The only allowed values for the Content-Type header in sendBeacon now are:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

I had a similar issue in our project and I ended up sending the data as 'text/plain; charset=UTF-8' and reading the stream on server side for the json content.

Client:

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

Server:

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

Not sure if this helps you.

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

Carniola answered 10/8, 2017 at 20:23 Comment(1)
Though not answering my use-case directly, it's helpful.Gulfweed
S
3

Note that the method seems to be broken on most browsers. Here's a large data study about the topic.

Snyder answered 17/12, 2019 at 12:33 Comment(0)
G
3

Short Answer: The issue has been resolved as of 2021.

Long Answer(background): I opened this issue some time back when I worked on timeonsite JS development. It used to work well in Chrome, Firefox & many other browsers. But, after few months, suddenly I got above CORS safelist error and failed to save time on site data real-time. It forced us to fallback on Localstorage which will result in (N-1) pageviews & subsequently lossy time-on-site data, a crucial web analytics metric, during each user session. And we have been eagerly waiting for this issue to be resolved from browser vendors. This is the configuration we used for capturing real-time that depends directly on 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> 

As you saw above, we have been commenting out sendBeacon() code block for last few years due to the CORS safelist issue and depended on XMLHTTPRequest with async=false to post data which is blocking approach and not quite reliable on many browsers especially on mobile devices.

Recently, it seems the issue has been resolved by browser vendors and sendBeacon() API is back for consumption. I tested across a number of browsers and it seems working fine. So, this issue is marked as "resolved" as of 2021. I would like you to add the devices/browsers that work well with version/year favorably mentioned for beforeunload/unload window events.

Gulfweed answered 23/11, 2021 at 6:17 Comment(2)
Chrome: version-95.0.4638.69, (2021) workingGulfweed
Firefox: version-94.0.1 (2021) workingGulfweed

© 2022 - 2024 — McMap. All rights reserved.