13

我的云功能在 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 请求的正文。

但是,当我将此主体用作测试中的触发事件时,我没有收到任何错误。所以我认为,我的工作中身体表现的问题,但我不知道如何解决它。我会很高兴有任何想法。

4

4 回答 4

18

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


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

场景一:通过 Cloud Scheduler 触发 Cloud Function

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

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

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

我发现了什么?

  • 当 GCF 例程通过 Cloud Scheduler 执行时,它会将标头发送content-typeapplication/octet-stream. 这使得 Express js 在 Cloud scheduler POST 数据时无法解析请求正文中的数据。
  • 但是当通过 Cloud Function 接口使用完全相同的请求正文来测试函数时,一切正常,因为接口上的测试功能将标头发送content-typeapplication/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 - 内容类型标头问题

于 2019-05-27T00:47:11.183 回答
11

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

request.get_json(force=True)

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

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

于 2020-03-10T09:57:43.680 回答
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)

完全同意,从可用性的角度来看,这是低于标准的。让测试实用程序通过 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"
于 2019-09-11T12:09:10.150 回答
1

您可以使用的一种解决方法是将标头“Content-Type”设置为“application/json”。你可以在这里看到一个设置。

于 2021-08-11T17:27:12.203 回答