Reputation: 7324
I have a simple app script that searches drive for a folder named 'something' and lists the names of files inside if the folder doesn't exist it creates it.
function doGet() {
var folders = DriveApp.getFoldersByName('something');
if (folders.hasNext()) {
var files = folders.next().getFiles();
var fileNames = [];
while (files.hasNext()) {
var file = files.next();
fileNames.push(file.getName())
};
return ContentService.createTextOutput(JSON.stringify({
'status': 'success',
'output': fileNames
}))
} else {
DriveApp.createFolder('something');
return ContentService.createTextOutput(JSON.stringify({
'status': 'success',
'output': 'folder created'
}))
}
}
I deploy the script as a web app, execute the app as myself, test it out using a fetch call from a react app in a browser and everything work as expected.
Then I republish as a web app, executing as the user accessing the web app. This time nothing works. I get the following error in the browser
Access to fetch at 'https://script.google.com/macros/s/AKfycbx4eQ60DziUy4hSjnJidW9WVwBsT_qruQHa_BrK508T4oD9ILY/exec' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I expected an error since there is no authentication. I set up google OAuth2 on the react app, added scripts and drive scopes, register the app in google developer console and set everything up so that I get an accessToken
that I can send in the header with the fetch call to the google script.
But I still get the same error as above.
How am I supposed to authorize an app script app so that anyone can run it?
I am trying to create a web app with a google
sign in button, when the user signins in it calls the appscript
I deployed and searches their drive for a folder names 'something' so that I can display the names of files in my web app.
This is not a cors issue, if I execute the web app as myself there is no cors problems and zero changes to the code. My question is regarding how I authorise an app script? I only mention the cors error because I was showing what I have tried so far.
Upvotes: 0
Views: 598
Reputation: 9862
You will receive a CORS error if any function in your call throws an exception, since you have no try...catch
handler. When a deployed webapp fails to return a valid response (i.e. either an HtmlOutput
or TextOutput
), Google's error page does not include any CORS headers.
To prevent these "masking" CORS errors, wrap your web app entry points with try...catch
so that the actual error can be reported.
Even without wrapping your webapp's entry points with try...catch
, it is very likely that you are able to access the underlying error by viewing your project's Stackdriver logs / Stackdriver Error Reporting.
This is a simple example, demonstrating some event object validation to ensure that the request is from somewhere you care about & is well-formed, and then calls a function that may throw an exception for invalid / unauthorized operations. In either case, it returns an opaque user-facing response ("Sorry!") and for errors will generate a Stackdriver log. It cannot catch the exception that occurs for an execution time quota breach, since your script is simply killed.
function doGet(e) {
if (!e || !validate_(e)) {
return fail_();
}
try {
return walkDriveContent(...);
}
catch (err) {
console.error({message: "Drive walk failed: " + err.message, stack: err.stack, error: err});
return fail_();
}
}
function fail_() {
return ContentService.createTextOutput("Sorry!");
}
function validate_(eventObj) {
/** your code here that ensures this is a valid event object you can work with */
// return true;
// or
// return false;
}
function walkDriveContent(folderName) {
/**
* Your code that may throw exceptions here, but otherwise
* returns TextOutput or HtmlOutput
*/
}
Upvotes: 1