Cross-domain requests stopped working due to no `Access-Control-Allow-Origin` header present in the response

I have an error reporting beacon I created using Google Apps script and it is published to run as myself and to be accessible to "anyone, even anonymous," which should mean that X-domain requests to GAS are allowed.

However, my browsers are now indicating there is no Access-Control-Allow-Origin header on the response after the code posts to the beacon.

Am I missing something here? This used to work as recently as two months ago. So long as the GAS was published for public access, then it was setting the Access-Control-Allow-Origin header.

In Google Apps Script:

Code.gs
function doPost(data){
  if(data){
        //Do Something
  }
  return ContentService.createTextOutput("{status:'okay'}", ContentService.MimeType.JSON);
}

Client Side:

script.js
$.post(beacon_url, data, null, "json");

Solution 1:

When making calls to a contentservice script I always have sent a callback for JSONP. Since GAS does not support CORS this is the only reliable way to ensure your app doesn't break when x-domain issues arrive.

Making a call in jQuery just add "&callback=?". It will figure everything else out.

 var url = "https://script.google.com/macros/s/{YourProjectId}/exec?offset="+offset+"&baseDate="+baseDate+"&callback=?";
 $.getJSON( url,function( returnValue ){...});

On the server side

function doGet(e){
 var callback = e.parameter.callback;
 //do stuff ...
 return ContentService.createTextOutput(callback+'('+ JSON.stringify(returnValue)+')').setMimeType(ContentService.MimeType.JAVASCRIPT);
}

Solution 2:

I've lost a couple of hours with the same issue. The solution was trivial.

When you deploy the script as webapp, you get two URLs: the /dev one and the /exec one. You should use /exec one to make cross domain POST requests. The /dev one is always private: it requires to be authorized and doesn't set *Allow-Origin header.

PS.: The /exec one seems to be frozen — it doesn't reflect any changes of code until you manually deploy it with a new version string (dropdown list in deploy dialog). To debug the most recent version of the script with the /dev URL just install an alternative browser and disable it's web-security features (--disable-web-security in GoogleChrome).

Solution 3:

Just to make it simpler for those who are only interested in a POST request like me:

function doPost(e){

 //do stuff ...

 var MyResponse = "It Works!";

 return ContentService.createTextOutput(MyResponse).setMimeType(ContentService.MimeType.JAVASCRIPT);

}

Solution 4:

I stumbled upon the same issue:

  • calling /exec-urls from the browser went fine when running a webpage on localhost
  • throws crossorigin-error when called from a https-domain

I was trying to avoid refactoring my POST JSON-clientcode into JSONP (I was skeptical, since things always worked before).

Possible Fix #1

Luckily, after I did one non-CORS request (fetch() in the browser from a https-domain, using mode: no-cors), the usual CORS-requests worked fine again.

last thoughts

A last explanation might be: every new appscript-deployment needs a bit of time/usage before its configuration actually settled down at server-level.