App Script sends 405 response when trying to send a POST request

Achala Dissanayake picture Achala Dissanayake · Jul 4, 2017 · Viewed 20.5k times · Source

I have published an app script publicly (Anyone, even anonymous) with a doPost method as follow,

 function doPost(e){
    var sheet = SpreadsheetApp.getActiveSheet();
    var length = e.contentLength;
    var body = e.postData.contents;
    var jsonString = e.postData.getDataAsString();
    var jsonData = JSON.parse(jsonString);
    sheet.appendRow([jsonData.title, length]);
    var MyResponse = "works";
    return ContentService.createTextOutput(MyResponse).setMimeType(ContentService.MimeType.JAVASCRIPT);
}

When I sent a Post request with a JSON object with Advanced Rest Client it all works and return a 200 OK response. But when I try to send a post request with the react axios from a locally hosted react app it sends a 405 Response.

XMLHttpRequest cannot load https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec. Response for preflight has invalid HTTP status code 405

I have enabled cross origin resource sharing in the browser as well. The function that sends the POST request is as follow,

axios({
          method:'post',
          url:'https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec',
          data: {
            "title": 'Fred',
            "lastName": 'Flintstone'
          }
        }).then(function (response) {
            console.log(response);
          })
          .catch(function (error) {
            console.log(error);
          });

Answer

Spooky picture Spooky · Oct 19, 2017

You missed the important part:

Response for preflight has invalid HTTP status code 405.

Your browser is making a preflight request, which uses the OPTIONS HTTP method. This is to check whether the server will allow the POST request – the 405 status code is sent in the response to the OPTIONS request, not your POST request.

A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood. Source


Additionally, for HTTP request methods that can cause side-effects on server's data (in particular, for HTTP methods other than GET, or for POST usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request method, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method. Source
Some requests don’t trigger a CORS preflight. Those are called "simple requests" in this article [...] Source
This article section details the conditions a request has to meet to be considered a "simple request".
[...] "preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. Source
This article section details the conditions which cause a request to be preflighted.

In this case, the following is causing the request to be preflighted:

[...] if the Content-Type header has a value other than the following:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

The value for the Content-Type header is set to application/json;charset=utf-8 by axios. Using text/plain;charset=utf-8 or text/plain fixes the problem:

axios({
    method: 'post',
    url: 'https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec',
    data: {
        title: 'Fred',
        lastName: 'Flintstone',
    },
    headers: {
        'Content-Type': 'text/plain;charset=utf-8',
    },
}).then(function (response) {
    console.log(response);
}).catch(function (error) {
    console.log(error);
});