Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 934
webblover Avatar asked Jul 24 '17 06:07

webblover


3 Answers

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

like image 178
Vidhi Khanna Avatar answered Nov 20 '22 19:11

Vidhi Khanna


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

like image 28
Tero Piirainen Avatar answered Nov 20 '22 19:11

Tero Piirainen


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.

like image 2
webblover Avatar answered Nov 20 '22 20:11

webblover