Escribe funciones HTTP

En Cloud Run Functions, usas funciones HTTP cuando quieres invocar una función a través de una solicitud HTTP(S). Para permitir la semántica de HTTP, las firmas de las funciones de HTTP aceptan argumentos específicos de HTTP.

Implementación

En el siguiente ejemplo, se muestra el archivo de origen de una función básica HTTP para cada entorno de ejecución. Consulta la Estructura del directorio del código fuente para obtener información sobre dónde ubicar el código fuente.

Node.js

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');
});

En Node.js, registra una función de controlador HTTP con Functions Framework para Node.js. Tu función de controlador HTTP debe ser una función de middleware exprés que acepte los argumentos de solicitud y respuesta y que envíe una respuesta HTTP.

Cloud Run Functions analiza el cuerpo de la solicitud de manera automática según el encabezado Content-Type de la solicitud mediante body-parser, para que puedas acceder a los objetos req.body y req.rawBody en tu controlador HTTP.

El punto de entrada de la función es el nombre con el que se registra el controlador en Functions Framework. En este ejemplo, el punto de entrada es 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'

En Python, registras una función de controlador HTTP con Functions Framework para Python. Tu función de controlador HTTP debe aceptar un objeto de solicitud de Flask como un argumento y mostrar un valor que Flask puede convertir en un objeto de respuesta HTTP.

El punto de entrada de la función es el nombre de la función del controlador registrada en Functions Framework. En este ejemplo, el punto de entrada es my_http_function.

Go

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")
}

En Go, registra una función de controlador HTTP con Functions Framework para Go en tu función init(). La función del controlador HTTP debe usar la interfaz http.HandlerFunc estándar para enviar una respuesta HTTP.

El punto de entrada de la función es el nombre con el que se registra el controlador en Functions Framework. En este ejemplo, el punto de entrada es MyHTTPFunction.

La función de tu controlador HTTP debe implementar la interfaz http.HandlerFunc estándar. Acepta una interfaz http.ResponseWriter que tu función usa para crear una respuesta a la solicitud, así como un puntero a una estructura http.Request que contiene los detalles de la solicitud HTTP entrante.

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");
  }
}

En Java, debes usar la API de Functions Framework para Java a fin de implementar una clase de controlador HTTP con la interfaz HttpFunction. El método service() debe enviar una respuesta HTTP.

El punto de entrada de la función es el nombre completamente calificado de la clase del controlador HTTP, incluido el nombre del paquete. En este ejemplo, el punto de entrada es myhttpfunction.MyHttpFunction.

Tu método service recibe un objeto HttpRequest que describe la solicitud HTTP entrante, así como un objeto HttpResponse que se propaga en tu función con un mensaje de respuesta.

C#

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");
        }
    }
}

En los entornos de ejecución de .NET, usas Functions Framework para .NET a fin de implementar una clase de controlador HTTP con la interfaz de IHttpFunction. El método HandleAsync() acepta un objeto HttpContext estándar de ASP.NET como argumento y debe enviar una respuesta HTTP.

El punto de entrada de la función es el nombre completamente calificado de la clase de controlador HTTP, incluido el espacio de nombres. En este ejemplo, el punto de entrada es 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

En Ruby, registras una función de controlador HTTP con Functions Framework para Ruby. La función de controlador HTTP debe aceptar un objeto de solicitud de Rack como argumento y mostrar un valor que se puede usar como respuesta HTTP.

El punto de entrada de la función es el nombre con el que se registra el controlador en Functions Framework. En este ejemplo, el punto de entrada es 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';
}

En PHP, registras una función de controlador HTTP con Functions Framework para PHP. Tu función de controlador HTTP debe aceptar un argumento que implemente la interfaz ServerRequestInterface de PSR-7 y debe mostrar una respuesta HTTP como una string o un objeto que implementa la interfaz ResponseInterface de PSR-7.

El punto de entrada de la función es el nombre con el que se registra el controlador en Functions Framework. En este ejemplo, el punto de entrada es myHttpFunction.

Solicitudes y respuestas HTTP

Las funciones HTTP aceptan los métodos de solicitud HTTP enumerados en la página activadores HTTP. Tu controlador HTTP puede inspeccionar el método de solicitud y realizar diferentes acciones en función del método.

Tu función debe enviar una respuesta HTTP. Si la función crea tareas en segundo plano (como subprocesos, futuros, objetos Promise de JavaScript, devoluciones de llamadas o procesos del sistema), debes finalizar o resolver estas tareas antes de enviar una respuesta HTTP. Es posible que no se completen todas las tareas que no se finalicen antes de enviar la respuesta HTTP, lo que puede causar un comportamiento indefinido.

Consulta Activadores de HTTP para obtener más información sobre las funciones HTTP y las opciones asociadas.

Cómo administrar CORS

El uso compartido de recursos entre dominios (CORS) es una forma de permitir que las aplicaciones que se ejecutan en un dominio accedan a los recursos de otro dominio. Por ejemplo, es posible que debas permitir que el dominio realice solicitudes al dominio de Cloud Run Functions para acceder a la función.

Si CORS no está configurado correctamente, es posible que veas errores como el siguiente:

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.

Para permitir solicitudes de origen cruzado a tu función, configura el encabezado Access-Control-Allow-Origin según corresponda en la respuesta HTTP. Para las solicitudes de origen cruzado con solicitud preliminar, debes responder a la solicitud OPTIONS preliminar con un código de respuesta 204 y encabezados adicionales.

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)

Go


// 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!");
  }
}

C#

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!');
    }
}

Limitaciones de CORS

Para las solicitudes preliminares de origen cruzado, las solicitudes OPTIONS preliminares se envían sin un encabezado Authorization, por lo que se rechazarán en todas las funciones HTTP que requieran autenticación. Como las solicitudes preliminares fallan, la solicitud principal también fallará. Para evitar esta limitación, usa una de las siguientes opciones:

Próximos pasos