我在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";。你可以在这里看到一个设置。