Облачная функция HTTP-запуска с планировщиком облака

У меня проблема с работой в облачном планировщике для моей облачной функции. Я создал работу со следующими параметрами:

Цель: 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 ответа


Отказ от ответственности: я пытался решить ту же проблему с помощью NodeJS, и я могу получить решение


Я понимаю, что это старый вопрос. Но я чувствовал, что стоит ответить на этот вопрос, поскольку я потратил почти 2 часа на то, чтобы найти ответ на этот вопрос.

Сценарий - 1: запуск облачной функции через облачный планировщик

  • Функция не может прочитать сообщение в теле запроса.

Сценарий - 2: Запуск облачной функции через вкладку "Тест" в интерфейсе облачной функции

  • Вызов функции всегда выполняется без ошибок.

Что я нашел?

  • Когда процедура GCF выполняется через Cloud Scheduler, она отправляет заголовок content-type как application/octet-stream. Из-за этого express js не может анализировать данные в теле запроса, когда облачный планировщик отправляет данные POST.
  • Но когда то же самое тело запроса используется для тестирования функции через интерфейс облачной функции, все работает нормально, потому что функция тестирования в интерфейсе отправляет заголовок.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 - проблема с заголовком типа контента

Другой способ решения проблемы - это:

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"

Один из обходных приемов, который вы можете использовать, - предоставить заголовок Content-Type, установленный на «application / json». Вы можете увидеть настройку здесь .

Другие вопросы по тегам