使用Cloud Scheduler的HTTP触发云功能



我在Cloud Scheduler中为我的云功能执行作业时遇到问题。我用下一个参数创建了作业:

目标:HTTP

URL:云功能的触发URL

HTTP方法:POST

正文

{
"expertsender": {
"apiKey": "ExprtSender API key",
"apiAddress": "ExpertSender APIv2 address",
"date": "YYYY-MM-DD",
"entities": [
{
"entity": "Messages"
},
{
"entity": "Activities",
"types":[
"Subscriptions"
]
}
]
},
"bq": {
"project_id": "YOUR GCP PROJECT",
"dataset_id": "YOUR DATASET NAME",
"location": "US"
} 
}

这个机构的实际价值已经改变了。

当我运行此作业时,我遇到了一个错误。原因是处理来自POST请求的正文。

然而,当我把这个主体作为测试中的触发事件使用时,我不会得到任何错误。所以我想,我的工作中身体代表的问题,但我不知道如何解决。我会很高兴有任何想法。


免责声明:我已经尝试使用NodeJS来解决同样的问题,并且我能够获得解决方案


我知道这是个老问题。但我觉得回答这个问题是值得的,因为我花了将近2个小时来找出这个问题的答案。

场景-1:通过云调度器触发云功能

  • 函数无法读取请求正文中的消息

场景-2:通过云功能界面中的测试选项卡触发云功能

  • 函数调用始终执行良好,没有错误

我发现了什么

  • 通过Cloud Scheduler执行GCF例程时,它会将标头content-type发送为application/octet-stream。这使得express js无法在云调度器发布数据时解析请求体中的数据
  • 但是,当使用完全相同的请求体通过Cloud function接口测试函数时,一切都很好,因为接口上的Testing功能将头content-type发送为application/json,express js能够读取请求体并将数据解析为JSON对象

解决方案

我必须手动将请求主体解析为JSON(基于内容类型标头显式使用if条件(,以获取请求主体中的数据。

/**
* Responds to any HTTP request.
*
* @param {!express:Request} req HTTP request context.
* @param {!express:Response} res HTTP response context.
*/
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
console.log('Headers from request: ' + JSON.stringify(req.headers));
let parsedBody;
if(req.header('content-type') === 'application/json') {
console.log('request header content-type is application/json and auto parsing the req body as json');
parsedBody = req.body; 
} else {
console.log('request header content-type is NOT application/json and MANUALLY parsing the req body as json');
parsedBody = JSON.parse(req.body);
}
console.log('Message from parsed json body is:' + parsedBody.message);
res.status(200).send(message);
};

这确实是谷歌必须解决的一个功能问题,希望谷歌能尽快解决。

Cloud Scheduler-内容类型标题问题

另一种解决问题的方法是:

request.get_json(force=True)

它强制解析器将有效负载视为json,而不是Mimetype。此处为烧瓶文件的参考

我认为这比提出的其他解决方案要简洁一些。

感谢@Dinesh将请求头作为解决方案!对于所有仍然徘徊和迷路的人,python 3.7.4:中的代码

import json
raw_request_data = request.data
# Luckily it's at least UTF-8 encoded...
string_request_data = raw_request_data.decode("utf-8")
request_json: dict = json.loads(string_request_data)

完全同意,从可用性的角度来看,这是不合格的。让测试实用程序传递一个JSON,而云调度程序发布一个"应用程序/八位位组流"是非常不负责任的设计。但是,如果您想以不同的方式调用函数,您应该创建一个请求处理程序:

def request_handler(request):
# This works if the request comes in from 
# requests.post("cloud-function-etc", json={"key":"value"})
# or if the Cloud Function test was used
request_json = request.get_json()
if request_json:
return request_json
# That's the hard way, i.e. Google Cloud Scheduler sending its JSON payload as octet-stream
if not request_json and request.headers.get("Content-Type") == "application/octet-stream":
raw_request_data = request.data
string_request_data = raw_request_data.decode("utf-8")
request_json: dict = json.loads(string_request_data)
if request_json:
return request_json
# Error code is obviously up to you
else:
return "500"

您可以使用的解决方法之一是提供一个头"内容类型";设置为";application/json";。你可以在这里看到一个设置。

相关内容

  • 没有找到相关文章

最新更新