应用程序脚本在尝试发送 POST 请求时发送 405 响应
App Script sends 405 response when trying to send a POST request
我已经公开发布了一个应用程序脚本(任何人,甚至是匿名的),使用 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 请求时,一切正常并且 return 200 OK 响应。但是,当我尝试从本地托管的 React 应用程序发送带有 React axios 的 post 请求时,它会发送 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);
});
我认为您需要 return JSON 数据。您可能需要 return JSONP 来响应来自浏览器的请求,但我认为您需要执行以下操作:
return ContentService.createTextOutput(JSON.stringify({message: MyResponse})).setMimeType(ContentService.MimeType.JSON);
如果这不起作用,可能是您需要在浏览器中 return JSONP 到 运行。这里有一些文档可以帮助您:https://developers.google.com/apps-script/guides/content#serving_jsonp_in_web_pages
你错过了重要的部分:
Response for preflight has invalid HTTP status code 405.
您的浏览器正在创建 preflight request, which uses the OPTIONS
HTTP 方法。这是为了检查服务器是否允许 POST
请求 - 405
状态代码是在对 OPTIONS
请求的响应中发送的,而不是您的 POST
请求。
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.
在这种情况下,以下原因导致请求被预检:
[...] if the Content-Type
header has a value other than the following:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Content-Type
header 的值被 axios 设置为 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
您可以使用 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)
})
我已经公开发布了一个应用程序脚本(任何人,甚至是匿名的),使用 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 请求时,一切正常并且 return 200 OK 响应。但是,当我尝试从本地托管的 React 应用程序发送带有 React axios 的 post 请求时,它会发送 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);
});
我认为您需要 return JSON 数据。您可能需要 return JSONP 来响应来自浏览器的请求,但我认为您需要执行以下操作:
return ContentService.createTextOutput(JSON.stringify({message: MyResponse})).setMimeType(ContentService.MimeType.JSON);
如果这不起作用,可能是您需要在浏览器中 return JSONP 到 运行。这里有一些文档可以帮助您:https://developers.google.com/apps-script/guides/content#serving_jsonp_in_web_pages
你错过了重要的部分:
Response for preflight has invalid HTTP status code 405.
您的浏览器正在创建 preflight request, which uses the OPTIONS
HTTP 方法。这是为了检查服务器是否允许 POST
请求 - 405
状态代码是在对 OPTIONS
请求的响应中发送的,而不是您的 POST
请求。
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 thanGET
, or forPOST
usage with certain MIME types), the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTPOPTIONS
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 theOPTIONS
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.
在这种情况下,以下原因导致请求被预检:
[...] if the
Content-Type
header has a value other than the following:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Content-Type
header 的值被 axios 设置为 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
您可以使用 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)
})