21

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");
Oleg Valter
  • 6,098
  • 6
  • 22
  • 37
Joshua Dannemann
  • 1,841
  • 1
  • 11
  • 30

7 Answers7

24

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);
}
Spencer Easton
  • 5,352
  • 1
  • 13
  • 25
  • 1
    I marked this as the answer, but it is a little off, so you might want to edit. For some reason, setting the content type inside createTextOutput, even with setting it to JavaScript does not fix the problem. However, using the function setContentType and setting it to JavaScript does work. Also, I am using a POST, and not a GET request in this use case. – Joshua Dannemann Apr 09 '15 at 17:20
  • 1
    Ah yea, JSONP will not work with Post. Everything you described sounds correct. Run the app as "me" allow access to "anonymous". Make sure you are making the call to the published address not the developer address. If all that is set you should have: Access-Control-Allow-Origin: * I've tested a small script with hurl.it. I'm seeing all the proper headers coming back from there. – Spencer Easton Apr 09 '15 at 18:14
  • Note that if for some reason there's an error in the script, it'll return text/html MIME type instead of JSON and then it'll result in a CORS error. So this may be the cause of your problem as well. – bryant1410 Aug 27 '19 at 17:41
11

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

SergeyR
  • 386
  • 3
  • 10
  • 1
    For future reference, this blog post seems to elaborate on this: [Google Apps Script Content Service - Cross Domain Puzzle](http://excelramblings.blogspot.com/2014/01/google-apps-script-content-service.html). Also quite relevant info here: [App Script sends 405 response when trying to send a POST request](https://stackoverflow.com/questions/44910180/app-script-sends-405-response-when-trying-to-send-a-post-request). As it seems, the /exec scope will by pass CORS as expected only in the cases of [simple requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Simple_requests). – Novack Jan 15 '19 at 20:02
  • 2
    @Novack you saved my day! Changing the request `Content-type` from `application/json` to AJAX default `application/x-www-form-urlencoded` solved my preflight 405 issue! – Jay Dadhania Dec 17 '19 at 02:22
  • 1
    Thank you SO much for adding that detail about how the code is frozen. I've been looking for hours, confused b/c I'm doing everything to the letter, and it was still giving me the CO error. I appreciate that they don't auto-version it so it doesn't make a billion versions of code for each time you change an alert, but at the same time it would have been nice to include a note on there that says, "Hey, if you're deploying this with new code, you need to specify a new version." – Ryan Feb 26 '20 at 14:52
6

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

}
David
  • 2,844
  • 2
  • 26
  • 47
  • 8
    This does not seem to work for me in 2018. I am still receiving the CORS error. – jj_ Feb 15 '18 at 02:30
  • 1
    @jj_ They start to work with /exec URL when you deploy your webapp. more details in my answer below. – SergeyR Jun 25 '18 at 22:21
  • Thanks for updating with other solutions, yeah this was a long time ago now! Still works for some though. – David Oct 14 '20 at 05:00
3

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.

coderofsalvation
  • 1,361
  • 12
  • 11
1

I faced a similar issue of CORS policy error when I tried to integrate the app script application with another Vue application.

Please be careful with the following configurations:

  1. Project version should be NEW for every deployment.
  2. Execute the app as me in case you want to give access to all.
  3. Who has access to the app to anyone, anonymous.

Hope this works for you.

srijan439
  • 91
  • 1
  • 5
0

My case is different, I'm facing the CORS error in a very weird way.

My code works normally and no CORS errors, only until I added a constant:

const MY_CONST = "...";

It seems that Google Apps Script (GAS) won't allow 'const' keyword, GAS is based on ES3 or before ES5 or that kind of thing. The error on 'const' redirect to an error page URL with no CORS.

Reference:
https://stackoverflow.com/a/54413892/5581893

datdinhquoc
  • 4,362
  • 4
  • 25
  • 47
0

In case this helps all any of those people like me:

I have a .js file which contains all my utility functions, including ones which call a GAS. I keep forgetting to clear my cache when I go to test updates, so I'll often get this kind of error because the cached code is using the /dev link instead of the /exec one.

Astrolamb
  • 153
  • 9