Escreva funções HTTP do Cloud Run

Nas funções do Cloud Run, escreve uma função HTTP quando quer invocar uma função através de um pedido HTTP(S). Para permitir a semântica HTTP, use o Function Framework e especifique a assinatura da função HTTP para aceitar argumentos específicos de HTTP.

Implemente funções de controlador HTTP

O exemplo seguinte mostra um ficheiro de origem de função HTTP básico para cada tempo de execução. Consulte a secção Estrutura do diretório de origem para obter informações sobre onde localizar o código-fonte.

Node.js

Módulo ES

  import { http } from '@google-cloud/functions-framework';
  http('myHttpFunction', (req, res) => {
    // Your code here

    // Send an HTTP response
    res.send('OK');
  });

Adicione as seguintes dependências, incluindo "type": "module" no ficheiro package.json:

  {
    "dependencies": {
      "@google-cloud/functions-framework": "^3.0.0"
    },
    "type": "module"
  }

Módulo CommonJS

  const functions = require('@google-cloud/functions-framework');

  // Register an HTTP function with the Functions Framework
  functions.http('myHttpFunction', (req, res) => {
    // Your code here

    // Send an HTTP response
    res.send('OK');
  });

Adicione as seguintes dependências no ficheiro package.json:

  {
    "dependencies": {
      "@google-cloud/functions-framework": "^3.0.0"
    }
  }

No Node.js, regista uma função de controlador HTTP com o Functions Framework para Node.js. A função do controlador HTTP tem de ser uma função de middleware do Express que aceite os argumentos request e response e envie uma resposta HTTP.

O Cloud Run analisa automaticamente o corpo do pedido com base no cabeçalho Content-Type do pedido através de body-parser, pelo que pode aceder aos objetos req.body e req.rawBody no seu controlador HTTP.

O ponto de entrada da função é o nome com o qual o controlador está registado no Functions Framework. Neste exemplo, o ponto de entrada é myHttpFunction.

Python

import functions_framework

# Register an HTTP function with the Functions Framework
@functions_framework.http
def my_http_function(request):
  # Your code here

  # Return an HTTP response
  return 'OK'

Em Python, regista uma função de controlador HTTP com o Functions Framework for Python. A função do controlador HTTP tem de aceitar um objeto Flask request como argumento e devolver um valor que o Flask possa converter num objeto de resposta HTTP.

O ponto de entrada da função é o nome com o qual o controlador está registado no Functions Framework. Neste exemplo, o ponto de entrada é my_http_function.

Ir

package myhttpfunction

import (
    "fmt"
    "net/http"

    "github.com/GoogleCloudPlatform/functions-framework-go/functions"
)

func init() {
    // Register an HTTP function with the Functions Framework
    functions.HTTP("MyHTTPFunction", myHTTPFunction)
}

// Function myHTTPFunction is an HTTP handler
func myHTTPFunction(w http.ResponseWriter, r *http.Request) {
    // Your code here

    // Send an HTTP response
    fmt.Fprintln(w, "OK")
}

Em Go, regista uma função de controlador HTTP com o Functions Framework para Go na sua função init(). A função do controlador HTTP tem de usar a interface http.HandlerFunc padrão para enviar uma resposta HTTP.

O ponto de entrada da função é o nome com o qual o controlador está registado no Functions Framework. Neste exemplo, o ponto de entrada é MyHTTPFunction.

A sua função de controlador HTTP tem de implementar a interface http.HandlerFunc padrão. Aceita uma interface http.ResponseWriter que a sua função usa para criar uma resposta ao pedido e um ponteiro para uma estrutura http.Request que contém os detalhes do pedido HTTP de entrada.

Java

package myhttpfunction;

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;

// Define a class that implements the HttpFunction interface
public class MyHttpFunction implements HttpFunction {
  // Implement the service() method to handle HTTP requests
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    // Your code here

    // Send an HTTP response
    response.getWriter().write("OK");
  }
}

Em Java, usa a API Java do Functions Framework para implementar uma classe de controlador HTTP com a interface HttpFunction. O método service() tem de enviar uma resposta HTTP.

O ponto de entrada da função é o nome totalmente qualificado da classe do controlador HTTP, incluindo o nome do pacote. Neste exemplo, o ponto de entrada é myhttpfunction.MyHttpFunction.

O seu método service recebe um objeto HttpRequest que descreve o pedido HTTP de entrada e um objeto HttpResponse que a sua função preenche com uma mensagem de resposta.

.NET

using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

namespace MyProject
{
    // Define a class that implements the IHttpFunction interface
    public class MyHttpFunction : IHttpFunction
    {
        // Implement the HandleAsync() method to handle HTTP requests
        public async Task HandleAsync(HttpContext context)
        {
            // Your code here

            // Send an HTTP response
            await context.Response.WriteAsync("OK");
        }
    }
}

Nos runtimes .NET, usa o Functions Framework para .NET para implementar uma classe de controlador HTTP com a interface IHttpFunction. O método HandleAsync() aceita um objeto ASP.NET padrão HttpContext como argumento e tem de enviar uma resposta HTTP.

O ponto de entrada da função é o nome totalmente qualificado da classe do controlador HTTP, incluindo o espaço de nomes. Neste exemplo, o ponto de entrada é MyProject.MyHttpFunction.

Ruby

require "functions_framework"

# Register an HTTP function with the Functions Framework
FunctionsFramework.http "my_http_function" do |request|
  # Your code here

  # Return an HTTP response
  "OK"
end

Em Ruby, regista uma função de controlador HTTP com o Functions Framework para Ruby. A sua função de controlador HTTP tem de aceitar um objeto de pedido Rack como argumento e devolver um valor que possa ser usado como resposta HTTP.

O ponto de entrada da função é o nome com o qual o controlador está registado no Functions Framework. Neste exemplo, o ponto de entrada é my_http_function.

PHP

<?php

use Google\CloudFunctions\FunctionsFramework;
use Psr\Http\Message\ServerRequestInterface;

// Register an HTTP function with the Functions Framework
FunctionsFramework::http('myHttpFunction', 'myHttpHandler');

// Define your HTTP handler
function myHttpHandler(ServerRequestInterface $request): string
{
    // Your code here

    // Return an HTTP response
    return 'OK';
}

Em PHP, regista uma função de controlador HTTP com o Functions Framework para PHP. A sua função de controlador HTTP tem de aceitar um argumento que implemente a interface PSR-7 ServerRequestInterface e tem de devolver uma resposta HTTP como uma string ou um objeto que implemente a interface PSR-7 ResponseInterface.

O ponto de entrada da função é o nome com o qual o controlador está registado no Functions Framework. Neste exemplo, o ponto de entrada é myHttpFunction.

Pedidos e respostas HTTP

Quando regista uma função de controlador HTTP com o Functions Framework, o seu controlador HTTP pode inspecionar o método de pedido e realizar diferentes ações com base no método.

Quando configura um fornecedor de eventos para enviar pedidos HTTP para a sua função do Cloud Run, a função envia uma resposta HTTP. Se a função criar tarefas em segundo plano (como com threads, futuros, objetos JavaScript Promise, callbacks ou processos do sistema), tem de terminar ou resolver estas tarefas antes de enviar uma resposta HTTP. As tarefas não terminadas antes de a resposta HTTP ser enviada podem não ser concluídas e podem causar um comportamento indefinido.

Processamento de CORs / compatibilidade com CORS

A partilha de recursos de origem cruzada (CORS) é uma forma de permitir que as aplicações executadas num domínio acedam a recursos de outro domínio. Por exemplo, pode ter de permitir que o seu domínio faça pedidos ao domínio das funções do Cloud Run para aceder à sua função.

Para permitir pedidos de origem cruzada à sua função, defina o cabeçalho Access-Control-Allow-Origin conforme adequado na sua resposta HTTP. Para pedidos de origem cruzada de verificação prévia, tem de responder ao pedido OPTIONS de verificação prévia com um código de resposta 204 e cabeçalhos adicionais.

Node.js

const functions = require('@google-cloud/functions-framework');

/**
 * HTTP function that supports CORS requests.
 *
 * @param {Object} req Cloud Function request context.
 * @param {Object} res Cloud Function response context.
 */
functions.http('corsEnabledFunction', (req, res) => {
  // Set CORS headers for preflight requests
  // Allows GETs from any origin with the Content-Type header
  // and caches preflight response for 3600s

  res.set('Access-Control-Allow-Origin', '*');

  if (req.method === 'OPTIONS') {
    // Send response to OPTIONS requests
    res.set('Access-Control-Allow-Methods', 'GET');
    res.set('Access-Control-Allow-Headers', 'Content-Type');
    res.set('Access-Control-Max-Age', '3600');
    res.status(204).send('');
  } else {
    res.send('Hello World!');
  }
});

Python

import functions_framework

@functions_framework.http
def cors_enabled_function(request):
    # For more information about CORS and CORS preflight requests, see:
    # https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request

    # Set CORS headers for the preflight request
    if request.method == "OPTIONS":
        # Allows GET requests from any origin with the Content-Type
        # header and caches preflight response for an 3600s
        headers = {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "GET",
            "Access-Control-Allow-Headers": "Content-Type",
            "Access-Control-Max-Age": "3600",
        }

        return ("", 204, headers)

    # Set CORS headers for the main request
    headers = {"Access-Control-Allow-Origin": "*"}

    return ("Hello World!", 200, headers)

Ir


// Package http provides a set of HTTP Cloud Functions samples.
package http

import (
	"fmt"
	"net/http"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
)

// CORSEnabledFunction is an example of setting CORS headers.
// For more information about CORS and CORS preflight requests, see
// https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request.
func CORSEnabledFunction(w http.ResponseWriter, r *http.Request) {
	// Set CORS headers for the preflight request
	if r.Method == http.MethodOptions {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "POST")
		w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
		w.Header().Set("Access-Control-Max-Age", "3600")
		w.WriteHeader(http.StatusNoContent)
		return
	}
	// Set CORS headers for the main request.
	w.Header().Set("Access-Control-Allow-Origin", "*")
	fmt.Fprint(w, "Hello, World!")
}

func init() {
	functions.HTTP("CORSEnabledFunction", CORSEnabledFunction)
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.BufferedWriter;
import java.io.IOException;
import java.net.HttpURLConnection;

public class CorsEnabled implements HttpFunction {
  // corsEnabled is an example of setting CORS headers.
  // For more information about CORS and CORS preflight requests, see
  // https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request.
  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    // Set CORS headers
    //   Allows GETs from any origin with the Content-Type
    //   header and caches preflight response for 3600s
    response.appendHeader("Access-Control-Allow-Origin", "*");

    if ("OPTIONS".equals(request.getMethod())) {
      response.appendHeader("Access-Control-Allow-Methods", "GET");
      response.appendHeader("Access-Control-Allow-Headers", "Content-Type");
      response.appendHeader("Access-Control-Max-Age", "3600");
      response.setStatusCode(HttpURLConnection.HTTP_NO_CONTENT);
      return;
    }

    // Handle the main request.
    BufferedWriter writer = response.getWriter();
    writer.write("CORS headers set successfully!");
  }
}

.NET

using Google.Cloud.Functions.Framework;
using Microsoft.AspNetCore.Http;
using System.Net;
using System.Threading.Tasks;

namespace Cors;

// For more information about CORS and CORS preflight requests, see
// https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request.
public class Function : IHttpFunction
{
    public async Task HandleAsync(HttpContext context)
    {
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;

        // Set CORS headers
        //   Allows GETs from any origin with the Content-Type
        //   header and caches preflight response for 3600s

        response.Headers.Append("Access-Control-Allow-Origin", "*");
        if (HttpMethods.IsOptions(request.Method))
        {
            response.Headers.Append("Access-Control-Allow-Methods", "GET");
            response.Headers.Append("Access-Control-Allow-Headers", "Content-Type");
            response.Headers.Append("Access-Control-Max-Age", "3600");
            response.StatusCode = (int) HttpStatusCode.NoContent;
            return;
        }

        await response.WriteAsync("CORS headers set successfully!", context.RequestAborted);
    }
}

Ruby

FunctionsFramework.http "cors_enabled_function" do |request|
  # For more information about CORS and CORS preflight requests, see
  # https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
  # for more information.

  # Set CORS headers for the preflight request
  if request.options?
    # Allows GET requests from any origin with the Content-Type
    # header and caches preflight response for an 3600s
    headers = {
      "Access-Control-Allow-Origin"  => "*",
      "Access-Control-Allow-Methods" => "GET",
      "Access-Control-Allow-Headers" => "Content-Type",
      "Access-Control-Max-Age"       => "3600"
    }
    [204, headers, []]
  else
    # Set CORS headers for the main request
    headers = {
      "Access-Control-Allow-Origin" => "*"
    }

    [200, headers, ["Hello World!"]]
  end
end

PHP


use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use GuzzleHttp\Psr7\Response;

function corsEnabledFunction(ServerRequestInterface $request): ResponseInterface
{
    // Set CORS headers for preflight requests
    // Allows GETs from any origin with the Content-Type header
    // and caches preflight response for 3600s
    $headers = ['Access-Control-Allow-Origin' => '*'];

    if ($request->getMethod() === 'OPTIONS') {
        // Send response to OPTIONS requests
        $headers = array_merge($headers, [
            'Access-Control-Allow-Methods' => 'GET',
            'Access-Control-Allow-Headers' => 'Content-Type',
            'Access-Control-Max-Age' => '3600'
        ]);
        return new Response(204, $headers, '');
    } else {
        return new Response(200, $headers, 'Hello World!');
    }
}

Se o CORS não estiver configurado corretamente, pode ver erros como os seguintes:

XMLHttpRequest cannot load https://YOUR_FUNCTION_URL.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'https://YOUR_DOMAIN' is therefore not allowed access.

Limitações de CORS

Para pedidos de origem cruzada pré-enviados, os pedidos OPTIONS pré-enviados são enviados sem um cabeçalho de autorização, pelo que são rejeitados em todas as funções HTTP que requerem autenticação. Uma vez que os pedidos de pré-voo falham, os pedidos principais também falham. Para contornar esta limitação, use uma das seguintes opções:

O que se segue?