Escribir funciones HTTP
En las funciones de Cloud Run, se usan funciones HTTP cuando se quiere invocar una función mediante una solicitud HTTP(S). Para permitir la semántica HTTP, las firmas de las funciones HTTP aceptan argumentos específicos de HTTP.
Implementación
En el siguiente ejemplo se muestra un archivo de origen de función HTTP básico para cada tiempo de ejecución. Consulta la sección Estructura del directorio de origen para obtener información sobre dónde encontrar 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, se registra una función de controlador HTTP con el Functions Framework para Node.js. Tu función de controlador HTTP debe ser una función de middleware de Express que acepte los argumentos request y response y envíe una respuesta HTTP.
Las funciones de Cloud Run analizan automáticamente el cuerpo de la solicitud en función del encabezado Content-Type
de la solicitud mediante body-parser
, por lo que puedes 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 el controlador se registra 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, se registra una función de controlador HTTP con el Functions Framework para Python. Tu función de controlador HTTP debe aceptar un objeto solicitud de Flask como argumento y devolver un valor que Flask pueda convertir en un objeto de respuesta HTTP.
El punto de entrada de la función es el nombre de la función de 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, registras una función de controlador HTTP con el
Functions Framework para Go
en tu función init()
. Tu función de controlador HTTP debe usar la interfaz estándar
http.HandlerFunc
para enviar una respuesta HTTP.
El
punto de entrada de la función
es el nombre con el que el controlador se registra en Functions Framework.
En este ejemplo, el punto de entrada es MyHTTPFunction
.
Tu función de controlador HTTP debe implementar la interfaz estándar http.HandlerFunc
. Acepta una interfaz http.ResponseWriter que tu función usa para crear una respuesta a la solicitud y 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, se usa la API Java de Functions Framework para 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 completo 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 y un objeto HttpResponse
que tu función rellena 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 tiempos de ejecución de .NET, se usa el Functions Framework para .NET para implementar una clase de controlador HTTP con la interfaz 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 completo de la clase del 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, se registra una función de controlador HTTP con el Functions Framework para Ruby. Tu función de controlador HTTP debe aceptar un objeto solicitud de Rack como argumento y devolver un valor que se pueda usar como respuesta HTTP.
El
punto de entrada de la función
es el nombre con el que el controlador se registra 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, se registra una función de controlador HTTP con el Functions Framework para PHP.
Tu función de controlador HTTP debe aceptar un argumento que implemente la interfaz PSR-7
ServerRequestInterface
y debe devolver una respuesta HTTP como una cadena o un objeto que implemente la interfaz PSR-7
ResponseInterface
.
El
punto de entrada de la función
es el nombre con el que el controlador se registra 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 que se indican 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 (por ejemplo, con hilos, futuros, objetos Promise
de JavaScript, retrollamadas o procesos del sistema), debes finalizar o resolver estas tareas antes de enviar una respuesta HTTP. Es posible que las tareas que no se hayan finalizado antes de que se envíe la respuesta HTTP no se completen y provoquen un comportamiento indefinido.
Consulta Triggers HTTP para obtener más información sobre las funciones HTTP y las opciones asociadas.
Gestión de 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 recursos de otro dominio. Por ejemplo, puede que tengas que permitir que tu dominio haga solicitudes al dominio de las funciones de Cloud Run para acceder a tu función.
Si CORS no está configurado correctamente, es posible que veas errores como los siguientes:
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 las solicitudes de origen cruzado a tu función, define el encabezado Access-Control-Allow-Origin
en la respuesta HTTP según corresponda. En el caso de las solicitudes de origen cruzado con comprobación previa, debes responder a la solicitud preparatoria OPTIONS
con un código de respuesta 204
y encabezados adicionales.
Node.js
Python
Go
Java
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
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
En el caso de las solicitudes de varios orígenes con comprobación previa, se envían solicitudes OPTIONS
de comprobación previa sin un encabezado Authorization
, por lo que se rechazarán en todas las funciones HTTP que requieran autenticación. Como las solicitudes de comprobación previa fallan, las solicitudes principales también fallarán. Para evitar esta limitación, usa una de las siguientes opciones:
- Permitir las invocaciones sin autenticar de tu función.
- Aloja tu aplicación web y tus funciones de Cloud Run en el mismo dominio para evitar CORS. Para ello, integra Firebase Hosting con funciones de Cloud Run.