使用Cloud Scheduler的HTTP触发云功能

Ser*_*nko 6 python google-cloud-functions google-cloud-scheduler

我的云功能在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"
       } 
}
Run Code Online (Sandbox Code Playgroud)

实际值已在此主体中更改。

当我运行此作业时,出现错误。原因是由于POST请求中的处理主体引起的。

但是,当我将此主体用作“测试”中的触发事件时,没有任何错误。因此,我认为这是我工作中身体表征的问题,但我不知道如何解决。任何想法我都会很高兴。

day*_*mos 10

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

request.get_json(force=True)
Run Code Online (Sandbox Code Playgroud)

它强制解析器将有效负载视为 json,从而引入 Mimetype。参考烧瓶文档是here

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


Gre*_*egK 6

感谢@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)
Run Code Online (Sandbox Code Playgroud)

完全同意,从可用性的角度来看,这是低于标准的。让测试实用程序通过 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"
Run Code Online (Sandbox Code Playgroud)


Din*_*vel 5


免责声明: 我已经尝试使用NodeJS解决相同的问题,并且能够找到解决方案


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

场景-1:通过Cloud Scheduler触发Cloud功能

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

场景-2:通过Cloud Function界面中的Test选项卡触发Cloud Function

  • 函数调用始终可以正常执行,没有错误。

我找到了什么?

  • 通过Cloud Scheduler执行GCF例程时,它将标头发送content-typeapplication/octet-stream。当Cloud Scheduler POST数据时,这使express js无法解析请求正文中的数据。
  • 但是,当使用完全相同的请求主体通过Cloud Function接口测试功能时,一切工作正常,因为接口上的Testing功能将标头发送为content-typeas 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);
};

Run Code Online (Sandbox Code Playgroud)

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

Cloud Scheduler-内容类型标题问题

  • 在追捕这个方面做得很好!只是给未来的访问者一个简短的说明,虽然您(还)不能通过控制台设置标题,但如果您通过 gcloud 创建调度程序作业,则可以设置标题(例如`gcloud scheduler jobs create ... --headers Content-Type=应用程序/json ...`)。相关文档目前隐藏在 [此页面](https://cloud.google.com/scheduler/docs/creating#) 上的模态中。 (3认同)
  • @ChadKruse 这是非常好的信息。我已经尝试过你的解决方案,它也有效。https://cloud.google.com/sdk/gcloud/reference/beta/scheduler/jobs/create/http#--headers (2认同)