javascriptgoogle-apps-scriptcors

CORS Error 405 (Method Not Allowed) - Google App Scripts


I have a very simple webpage, that only has a button which should submit the POST below to my google app scripts code. When testing, I click the button to run the SendTest() function and get the following error in the console:

Access to fetch at 'https://script.google.com/macros/s/[redacted]/exec' from origin 'http://127.0.0.1:5500' 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.

On the Network tab, I see the OPTIONS request, but it returns a 405 Method Not Allowed error. I have tried manually adding the header with no luck.

Any point in the right direction would be greatly appreciated.

Simplified HTML / JS Code:

<!DOCTYPE html>
<button onclick="sendTest()">Send Test POST</button>
<script>
async function sendTest() {
  try {
    const payload = {
      responses: [
        { category: 'Test', question: 'Q?', recommendation: 'Do X' }
      ]
    };

    console.log('Sending:', JSON.stringify(payload));

    const response = await fetch('https://script.google.com/macros/s/[redacted]/exec', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload),
      mode: 'cors',
      credentials: 'omit'
    });

    console.log('Response status:', response.status);
    console.log('Response headers:', [...response.headers.entries()]);

    if (!response.ok) {
      const errorText = await response.text();
      throw new Error(`HTTP error! Status: ${response.status}, Details: ${errorText}`);
    }
    const result = await response.json();
    console.log('Response:', result);
  } catch (error) {
    console.error('Fetch error:', error);
  }

}

Google App Script Code:

function doGet(e) {
var output = JSON.stringify({
status: 'success',
message: 'It worked',
});

return ContentService.createTextOutput(output)
.setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
 return ContentService.createTextOutput(JSON.stringify({status: "success", "data": "my-data"})).setMimeType(ContentService.MimeType.JSON);
}
function doOptions(e) {
  const output = ContentService.createTextOutput('');
  output.setMimeType(ContentService.MimeType.TEXT);
  output.addHeader('Access-Control-Allow-Origin', '*');
  output.addHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
  output.addHeader('Access-Control-Allow-Headers', 'Content-Type');
  return output;
}

Solution

  • In your script, please modify Javascript as follows.

    From:

    const response = await fetch('https://script.google.com/macros/s/[redacted]/exec', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload),
      mode: 'cors',
      credentials: 'omit'
    });
    

    To:

    const response = await fetch('https://script.google.com/macros/s/[redacted]/exec', {
      method: 'POST',
      body: JSON.stringify(payload),
    });
    

    or

    const response = await fetch('https://script.google.com/macros/s/[redacted]/exec', {
      method: 'POST',
      body: JSON.stringify(payload),
      headers: { "Content-Type": "text/plain" }
    });
    

    Note:

    References: