【问题标题】:App Script sends 405 response when trying to send a POST request尝试发送 POST 请求时,应用脚本发送 405 响应
【发布时间】:2017-12-08 04:12:06
【问题描述】:

我已经使用 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);
}

当我使用 Advanced Rest Client 发送带有 JSON 对象的 Post 请求时,它一切正常并返回 200 OK 响应。但是,当我尝试从本地托管的 react 应用程序发送带有 react axios 的发布请求时,它会发送 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);
          });

【问题讨论】:

  • 尝试POST 而不是post,这为我解决了类似的问题

标签: google-apps-script axios cors http-status-code-405


【解决方案1】:

你错过了重要的部分:

预检响应包含无效的 HTTP 状态代码 405。

您的浏览器正在创建preflight request,它使用OPTIONS HTTP 方法。这是为了检查服务器是否允许 POST 请求 - 405 状态代码是在对 OPTIONS 请求的响应中发送的,而不是您的 POST 请求。

CORS 预检请求是一个CORS 请求,用于检查是否理解 CORS 协议。 Source


此外,对于可能对服务器数据造成副作用的 HTTP 请求方法(特别是对于 GET 以外的 HTTP 方法,或者对于 POST 与某些 MIME types 的使用),规范要求浏览器“预检”请求,使用 HTTP OPTIONS 请求方法从服务器请求支持的方法,然后,在服务器“批准”后,使用实际的 HTTP 请求方法发送实际请求。 Source
有些请求不会触发CORS preflight。这些在本文中被称为“简单请求”[...]Source
本文部分详细说明了请求必须满足的条件才能被视为“简单请求”。 [...]“预检”请求首先通过 OPTIONS 方法向另一个域上的资源发送 HTTP 请求,以确定实际请求是否可以安全发送。跨站点请求是这样预检的,因为它们可能对用户数据有影响。 Source
本文部分详细介绍了导致请求被预检的条件。

在这种情况下,以下是导致请求被预检的原因:

[...] 如果 Content-Type 标头的值不是以下值:

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

Content-Type 标头的值被 axios 设置为 application/json;charset=utf-8。使用text/plain;charset=utf-8text/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);
});

【讨论】:

  • “405 状态码是在对 OPTIONS 请求的响应中发送的,而不是您的 POST 请求”这部分我知道,但我的印象是浏览器会为所有发布请求发送预检。 “如果 Content-Type 标头的值不是以下值:...”这部分我不知道。尽管我解决了一个问题,但我现在不完全记得了,但我会将此标记为答案而无需测试,因为我正在寻找的也是避免预检。谢谢你的回答:)
  • 这帮助我避免了预检(因此避免了 405),非常感谢!!!
【解决方案2】:

对于将来遇到此问题的人的另一种方法:

(在我的情况下,使用 'Content-Type': 'text/plain;charset=utf-8' 不起作用)

根据这个文档https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format

您可以使用application/x-www-form-urlencoded,而不是使用text/plain;charset=utf-8 作为接受的答案:

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

【讨论】:

    【解决方案3】:

    我认为您需要返回 JSON 数据。您可能需要将 JSONP 返回到来自浏览器的请求,但我认为您需要这样做:

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

    如果这不起作用,可能是您需要返回 JSONP 才能在浏览器中运行。这里有一些文档可以帮助你:https://developers.google.com/apps-script/guides/content#serving_jsonp_in_web_pages

    【讨论】:

    • 另一件事...确保部署为新版本。不要只是更新。
    猜你喜欢
    • 2017-03-01
    • 2020-07-29
    • 2017-10-12
    • 2018-09-16
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 2018-02-09
    • 2015-04-20
    相关资源
    最近更新 更多