使用 Cloud Scheduler 触发 Cloud Functions 的 HTTP
Posted
技术标签:
【中文标题】使用 Cloud Scheduler 触发 Cloud Functions 的 HTTP【英文标题】:HTTP Triggering Cloud Function with Cloud Scheduler 【发布时间】:2019-04-12 11:01:51 【问题描述】:我的云功能在 Cloud Scheduler 中的作业有问题。我使用下一个参数创建了作业:
目标:HTTP
网址:我的云功能触发网址
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 请求的正文。
但是,当我将此主体用作测试中的触发事件时,我没有收到任何错误。所以我认为,我的工作中身体表现的问题,但我不知道如何解决它。有任何想法我都会很高兴。
【问题讨论】:
错误是什么?正文内容是什么? @DougStevenson 当我试图在云函数中获取身体数据时发生错误(我使用 python)。因此,我的函数获取了正文,但随后我在日志中看到:“NoneType”对象不可下标。这意味着,该函数无法正确提取主体中的参数,因为主体有问题。但是,当我从具有相同主体的云功能的测试界面触发我的功能时,不会发生错误。我在上面的一个问题中留下的正文内容。 您可能想要编辑您的问题以显示您的代码并指出发生错误的行。您还应该展示您期望的正文内容。 您能否也包括包含“'NoneType' 对象不可下标”的整个日志消息? @SergeyKravchenko 你能用更多细节更新这个问题吗? 【参考方案1】:免责声明: 我尝试使用 NodeJS 解决相同的问题,并且我能够得到解决方案
我知道这是一个老问题。但我觉得值得回答这个问题,因为我花了将近 2 个小时来找出这个问题的答案。
场景一:通过云调度器触发云函数
函数无法读取请求正文中的消息。场景二:通过 Cloud Function 界面中的 Test 选项卡触发 Cloud Function
函数调用始终可以正常执行,没有错误。我发现了什么?
当 GCF 例程通过 Cloud Scheduler 执行时,它将标头content-type
发送为 application/octet-stream
。这使得在 Cloud scheduler POST 数据时 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);
;
这确实是 Google 必须解决的功能问题,希望 Google 尽快解决。
Cloud Scheduler - Content Type header issue
【讨论】:
在追查这个问题上做得很好!只是给未来访问者的一个快速说明,虽然您不能通过控制台设置标题(还),但如果您通过 gcloud 创建调度程序作业(例如gcloud scheduler jobs create ... --headers Content-Type=application/json ...
),则可以设置标题。相关文档目前隐藏在this page 的模态中。
@ChadKruse 这是非常好的信息。我已经尝试过您的解决方案,它也可以正常工作。 cloud.google.com/sdk/gcloud/reference/beta/scheduler/jobs/…【参考方案2】:
感谢@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"
【讨论】:
【参考方案3】:解决问题的另一种方法是:
request.get_json(force=True)
它强制解析器将有效负载视为 json,输入 Mimetype。 参考烧瓶文档是here
我认为这比其他建议的解决方案更简洁。
【讨论】:
【参考方案4】:您可以使用的一种解决方法是将标头“Content-Type”设置为“application/json”。你可以看到一个设置here。
【讨论】:
以上是关于使用 Cloud Scheduler 触发 Cloud Functions 的 HTTP的主要内容,如果未能解决你的问题,请参考以下文章
如何将属性从 Cloud Scheduler 传递到 Pub/Sub?
尝试运行 Cloud Run 作业时,Cloud Scheduler 的权限被拒绝
Cloud Scheduler 不尊重我的超时设置(编辑:与 CloudRun 无关)
尝试运行 Google Cloud Scheduler 任务时出现 PERMISSION_DENIED 错误
spring-cloud-alibaba-sentinel和feign配合使用,启动报Caused by: java.lang.AbstractMethodError: com.alibaba.clo