2

I make a POST request from Chrome extension to a GAS deployed as Web App. Chrome extension script is:

const fetchData = async (scriptURL, data) => {
        try {
            const response = await fetch(scriptURL, {
                mode: 'no-cors',
                method: 'POST',
                referrer: "",
                redirect: 'follow',
                body: JSON.stringify(data), 
                headers: {
                    'Content-Type': 'application/json',
                    'Access-Control-Allow-Origin':'*'
                }                        
            });                             
            if (response != "") var json = response.json();
            console.log('Success:', JSON.stringify(json));
        } 
        catch (e){console.log('Errors:', e.message)}       
            
        return json;
    }

The Web App gets request, processes it and returns a JSON response:

 function doPost(e){ 
          // processing
    return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);
}

Although Chrome extension doesn't get back respose body. Chrome gives an error "Failed to load response data" in DevTools->Network->Response . Here are the request and response headers:

Request URL: https://script.google.com/macros/s/AKfycbzwUUktSYViIkE-kEc9-C73ztt6Mm14GTW9tEFezIdt/exec
Request Method: POST
Status Code: 302 
Remote Address: 173.194.220.100:443
Referrer Policy: no-referrer-when-downgrade
**Response headers**
access-control-allow-origin: *
alt-svc: h3-29=":443"; ma=2592000, h3-27=":443"; ma=2592000, h3-25=":443"; ma=2592000, h3-T050=":443"; ma=2592000, h3-Q050=":443"; ma=2592000, h3-Q046=":443"; ma=2592000, h3-Q043=":443"; ma=2592000
cache-control: no-cache, no-store, max-age=0, must-revalidate
content-encoding: gzip
content-length: 416
content-security-policy: script-src 'report-sample' 'nonce-DROk3lWJaG4CuCxaaXZ+iQ' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;object-src 'none';base-uri 'self';report-uri /cspreport
content-type: text/html; charset=UTF-8
date: Mon, 06 Jul 2020 19:16:47 GMT
expires: Mon, 01 Jan 1990 00:00:00 GMT
location: https://script.googleusercontent.com/macros/echo?user_content_key=3VuZ5HCCoG5098DqNcdFBjLL5kKYEi5U0ifWB9YmhR6BwH8VqCvsX8_sSZeRVkJwP1fZuSegpbhbvW6kPGda1I-6C2vyPPLIm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnOhtPz9z4I3dzdyyINU3UA0pwpiENh8R4k1UDc5fBUkkDEzr0xNxtlsP-6Y5oFxMMg&lib=MpU1M31wDqWrblgsshTKAbKcDiPyCPu1i
pragma: no-cache
server: GSE
set-cookie: SIDCC=AJi4QfGj_nmaK5xHhkEGWyyb7dSsxg04uiw5Jp1HBnHCqmfBXd2win3dnlpVNNPsFuGVbqfUZ71m; expires=Tue, 06-Jul-2021 19:16:47 GMT; path=/; domain=.google.com; priority=high
status: 302
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-xss-protection: 1; mode=block
**Request Headers**
:authority: script.google.com
:method: POST
:path: /macros/s/AKfycbzwUUktSYViIkE-kEc9-C73ztt6Mm14GTW9tEFezIdt/exec
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
content-length: 344
content-type: text/plain;charset=UTF-8
cookie: .........
origin: chrome-extension://gabejmdkdkojddbfifhcceicplhpdkmn
sec-fetch-dest: empty
sec-fetch-mode: no-cors
sec-fetch-site: none
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
x-client-data: CIe2yQEIorbJAQjBtskBCKmdygEI/rzKAQjAvcoBCOfIygEYm77KAQ==

It looks like a problem with CORS (headers, or google server returns opaque response or etc).

Marios
  • 26,333
  • 8
  • 32
  • 52
Sturmer
  • 45
  • 5
  • No, it is not a CORS error, see list of [possible errors on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors). `googleusercontent` is where actual content is served when you return text content from a Web App. Just follow the `location` header - not sure why `fetch` did not follow it – Oleg Valter is with Ukraine Jul 06 '20 at 19:54
  • 1
    Does this answer your question? [XMLHttpRequest blocked by CORS policy when posting data to a Web App](https://stackoverflow.com/questions/62587453/xmlhttprequest-blocked-by-cors-policy-when-posting-data-to-a-web-app) – TheMaster Jul 06 '20 at 20:45
  • @TheMaster - do you think this is a cors issue after all (and apologies for responding to an automated message)? Looks like a response that could just be followed to googleusercontent no problem – Oleg Valter is with Ukraine Jul 06 '20 at 20:49
  • 1
    @OlegValter My theory is OP didn't show the "follow" network request , which happens after what OP showed and then *Failed to load response data*. There's no reason for the error if it's just 302. And preflighted requests will surely fail. And "no-cors" will only return a "opaque filtered response"( === nothing )=> This agrees with *Chrome extension doesn't get back respose body*. So yeah it's a guess;) – TheMaster Jul 06 '20 at 21:02
  • 1
    @TheMaster - ah I see your reasoning now, hm. Would be nice to see some clarifications on that - @Sturmer? Certainly opaque response part should be as you mentioned. Btw, likely related (although not a dupe target): on ["Failed to load response data"](https://stackoverflow.com/questions/38924798/chrome-dev-tools-fails-to-show-response-even-the-content-returned-has-header-con) – Oleg Valter is with Ukraine Jul 06 '20 at 21:12
  • Oleg Valter, opaque response is my guess. I tried to use "cors' mode, but got an error: "Access to fetch at 'https://.. (redirected from 'https://...) from origin 'chrome-extension://... 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." – Sturmer Jul 06 '20 at 22:10
  • It looks that google server responds with opaque response. this may be due to its settings or to peculiarities of WEB App. If it's settings where they are? – Sturmer Jul 06 '20 at 22:15
  • @Sturmer - I see (you should include the info in your question). Re:settings - Web Apps lack a lot in terms of customization, so no, there are no cors settings. Re:opaque - this is a very specific concept, see [this](https://stackoverflow.com/questions/36292537/what-is-an-opaque-response-and-what-purpose-does-it-serve) and [this](https://stackoverflow.com/questions/39109789/what-limitations-apply-to-opaque-responses) Q&Aa for details. See also [this one](https://stackoverflow.com/questions/43871637/no-access-control-allow-origin-header-is-present-on-the-requested-resource-whe) for "no header" – Oleg Valter is with Ukraine Jul 06 '20 at 22:31
  • 1
    I proposed a modified script for your issue. Could you please confirm it? If that was not the result you expect, I apologize. – Tanaike Jul 06 '20 at 22:49
  • 1
    Just change contentType to "text/plain". Everything will work out on it's own. – TheMaster Jul 07 '20 at 13:37
  • 1
    TheMaster, Just changing of contentType to "text/plain" doesn't work. I checked it. – Sturmer Jul 07 '20 at 20:55

1 Answers1

3

In this case, I would like to propose to modify as follows.

Modification points:

  • In my experience for using Web Apps of doPost using fetch, I have understood that the following simple script can be used. Ref

      fetch(url, { method: "POST", body: JSON.stringify(obj) })
        .then((res) => {
          console.log(res.status);
          return res.text();
        })
        .then((res) => console.log(res));
    
  • In this case, when headers is used, I confirmed that the error related to CORS occurs. And, at Web Apps, it seems that e.postData.contents of doPost(e) is the same with and without this headers.

From above script, when your script is modified, it becomes as follows.

Modified script:

const fetchData = async (scriptURL, data) => {
  var json;
  try {
    const response = await fetch(scriptURL, {
      method: 'POST',
      body: JSON.stringify(data),
    });
    if (response != "") json = await response.json();
    console.log('Success:', JSON.stringify(json));
  } catch (e) {
    console.log('Errors:', e.message)
  }
  return json;
}

async function main() {
  const res = await fetchData("https://script.google.com/macros/s/###/exec", {key1: "value1"});
  console.log(res);
}

main();
  • I could confirm that when this modified script is used, no error occurs for requesting to doPost.

Note:

  • In this modification, it supposes that response of return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON); has the value. When Google Apps Script has the errors, above modified script doesn't work. So please be careful this.

  • I think that at first, in order to confirm whether the above script can be used, for example, I would like to recommend to do use the following simple sample script.

      function doPost(e){ 
        return ContentService.createTextOutput(JSON.stringify(e)).setMimeType(ContentService.MimeType.JSON);
      }
    
  • When you modified the Google Apps Script of Web Apps, please redeploy the Web Apps as new version. By this, the latest script is reflected to the Web Apps. Also, please be careful this.

References:

Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • 1
    @Sturmer - please, try to notify answerers of the post first before editing (if the edit does more than fixes the error). Still - thank you for findin the typo - @Tanaike, promise fulfillment operator is missing in `response.json()` – Oleg Valter is with Ukraine Jul 07 '20 at 21:06
  • 1
    @Oleg Valter Thank you for your comment. I could understand about it. – Tanaike Jul 07 '20 at 22:21
  • 1
    @Sturmer Thank you for replying. I'm glad your issue was resolved. – Tanaike Jul 07 '20 at 22:22