Сценарий приложения отправляет 405 ответ при попытке отправить запрос POST

Я публично опубликовал сценарий приложения (любой, даже анонимный) с помощью метода doPost следующим образом:

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

Когда я отправляю запрос Post с объектом JSON с помощью Advanced Rest Client, все это работает и возвращает ответ 200 OK. Но когда я пытаюсь отправить почтовый запрос с помощью axio реагирования из локально размещенного приложения реакции, он отправляет ответ 405.

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

Я также включил общий доступ к ресурсам в браузере. Функция, которая отправляет запрос POST, выглядит следующим образом:

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

Если кто-то может указать мне, почему я получаю ответ 405, был бы благодарен.

4 ответа

Решение

Вы пропустили важную часть:

Ответ на предпечатную проверку имеет недопустимый код состояния HTTP 405.

Ваш браузер выполняет предварительный запрос, который использует OPTIONS HTTP метод. Это делается для того, чтобы проверить, разрешит ли сервер POST запрос - 405 код состояния отправляется в ответ на OPTIONS запрос, а не ваш POST запрос.

Предварительный запрос CORS - это запрос CORS, который проверяет, понятен ли протокол CORS. Источник


Кроме того, для методов HTTP-запроса, которые могут вызывать побочные эффекты на данных сервера (в частности, для методов HTTP, отличных от GET или для POST использование с определенными типами MIME), спецификация требует, чтобы браузеры "предварительно отправляли" запрос, запрашивая поддерживаемые методы с сервера с HTTP OPTIONS метод запроса, а затем, после "одобрения" с сервера, отправка фактического запроса с фактическим методом HTTP-запроса. Источник
Некоторые запросы не запускают предварительную проверку CORS. Это так называемые "простые запросы" в этой статье [...] Source
В этом разделе статьи подробно описываются условия, которым должен соответствовать запрос, чтобы он считался "простым запросом".
[...] "предварительные" запросы сначала отправляют HTTP-запрос OPTIONS метод для ресурса в другом домене, чтобы определить, является ли фактический запрос безопасным для отправки. Межсайтовые запросы предварительно просматриваются следующим образом, так как они могут иметь значение для пользовательских данных. Источник
В этом разделе статьи подробно описываются условия, которые вызывают предварительную проверку запроса.

В этом случае следующий запрос вызывает предварительную проверку запроса:

[...] если Content-Type заголовок имеет значение, отличное от следующего:

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

Значение для Content-Type заголовок установлен в application/json;charset=utf-8 по оси. С помощью text/plain;charset=utf-8 или же text/plain решает проблему:

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

Другой способ для тех, кто столкнется с этой проблемой в будущем:

(в моем случае, используя 'Content-Type': 'text/plain;charset=utf-8' не работает)

Согласно этому документу https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format

Вместо того, чтобы использовать text/plain;charset=utf-8 в качестве принятого ответа вы можете использовать application/x-www-form-urlencoded:

const axios = require('axios')
const qs = require('qs')

const url = 'https://script.google.com/macros/s/AKfycbzyc2CG9xLM-igL3zuslSmNY2GewL5seTWpMpDIQr_5eCod7_U/exec'

const data = {
        "title": 'Fred',
        "lastName": 'Flintstone'
}

const options = {
  method: 'POST',
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
  data: qs.stringify(data),
  url
}

axios(options)
  .then(function(response) {
    console.log(response.data)
  })
  .catch(function(error) {
    console.log(error)
  })

Я думаю, что вам нужно вернуть данные JSON. Возможно, вам нужно вернуть JSONP к запросу из браузера, но я думаю, что вам нужно сделать следующее:

return ContentService.createTextOutput(JSON.stringify({message: MyResponse})).setMimeType(ContentService.MimeType.JSON);

Если это не сработает, возможно, вам нужно вернуть JSONP для запуска в браузере. Вот некоторая документация, чтобы помочь вам: https://developers.google.com/apps-script/guides/content

ПРОВЕРЬТЕ НАЗВАНИЯ МЕТОДА ЗАПРОСА API И КОНЕЧНОЙ ТОЧКИ API!

Я отправлял запрос POST на конечную точку GET. Это возвращает ошибку HTTP 405.

Другие вопросы по тегам