Cloud Run-Funktionen schreiben

Auf dieser Seite wird beschrieben, wie Sie HTTP- und ereignisgesteuerte Cloud Run-Funktionen mit dem Functions Framework schreiben.

Functions Framework – Übersicht

Beim Schreiben von Quellcode für Funktionen müssen Sie das Functions Framework verwenden, eine Open-Source-Bibliothek zum Schreiben von Cloud Run Functions. Mit dem Functions Framework können Sie einfache Funktionen schreiben, die in Cloud Run und anderen Umgebungen ausgeführt werden, einschließlich Ihrer lokalen Entwicklungsmaschine und Knative-basierten Umgebungen.

Mit dem Functions Framework können Sie:

  • Eine Cloud Run-Funktion als Reaktion auf eine Anfrage aufrufen.
  • Ereignisse, die der Spezifikation CloudEvents entsprechen, automatisch umwandeln. CloudEvents ist eine branchenweit übliche Spezifikation zum allgemeinen Beschreiben von Ereignisdaten.
  • Starten Sie einen lokalen Entwicklungsserver zum Testen.

Das Functions Framework bietet eine Schnittstelle zum Erstellen modularer Dienste. Wenn Sie das Functions Framework in Ihrem Quellcode verwenden möchten, geben Sie Folgendes an:

Funktionseinstiegspunkt

Ihr Quellcode muss einen Funktionseinstiegspunkt definieren. Das ist der Code, der ausgeführt wird, wenn Cloud Run Ihre Funktion aufruft. Sie geben diesen Einstiegspunkt an, wenn Sie die Funktion bereitstellen.

Wie Sie den Einstiegspunkt definieren, hängt von der verwendeten Sprachlaufzeit ab. Bei einigen Sprachen ist der Einstiegspunkt eine Funktion, bei anderen ist der Einstiegspunkt eine Klasse.

Signaturtyp

Wenn Sie den Quellcode einer Funktion mit dem Functions Framework schreiben, müssen Sie einen der beiden Signaturtypen angeben:

  • HTTP-Funktionen: Registriert eine HTTP-Handlerfunktion. Verwenden Sie eine HTTP-Funktion, wenn Ihre Funktion einen URL-Endpunkt haben und auf HTTP-Anfragen antworten muss, z. B. für Webhooks.
  • Ereignisgesteuerte Funktionen, auch bekannt als CloudEvents-Funktionen: Registriert eine CloudEvents-Handler-Funktion. Verwenden Sie eine ereignisgesteuerte Funktion, wenn Ihre Funktion direkt als Reaktion auf Ereignisse in Ihrem Google Cloud -Projekt ausgelöst werden soll, z. B. Nachrichten in einem Pub/Sub-Thema oder Änderungen in einem Cloud Storage-Bucket.

Struktur des Quellverzeichnisses

Das Functions Framework wird in einer Reihe von Programmiersprachen unterstützt. Die von Ihnen ausgewählte Sprachlaufzeit und der Typ der Funktion, die Sie schreiben möchten, bestimmen, wie Sie Ihren Code strukturieren und Ihre Funktion implementieren.

Damit Cloud Run Ihre Funktionsdefinition finden kann, benötigt jede Sprachlaufzeit Anforderungen zum Strukturieren Ihres Quellcodes.

Node.js

Die grundlegende Verzeichnisstruktur für Node.js-Funktionen sieht so aus:

.
├── index.js
└── package.json

Standardmäßig versucht Cloud Run, Quellcode aus einer Datei mit dem Namen index.js im Stammverzeichnis Ihres Funktionsverzeichnisses zu laden. Verwenden Sie das Feld main in der Datei package.json, um eine andere Hauptquelldatei anzugeben.

Die Datei package.json muss auch das Functions Framework für Node.js als Abhängigkeit enthalten:

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

Der Code in der Hauptdatei muss den Funktionseinstiegspunkt definieren und kann anderen Code und Node.js-Module importieren. Die Hauptdatei kann auch mehrere Funktionseinstiegspunkte definieren, die separat bereitgestellt werden können.

Weitere Informationen finden Sie in der Übersicht über die Node.js-Laufzeit und im Functions Framework für Node.js.

Python

Die grundlegende Verzeichnisstruktur für Python-Funktionen sieht so aus:

.
├── main.py
└── requirements.txt

Cloud Run lädt den Quellcode aus einer Datei namens main.py im Stammverzeichnis Ihres Funktionsverzeichnisses. Die Hauptdatei muss main.py heißen.

Die Datei requirements.txt muss das Functions Framework für Python als Abhängigkeit enthalten:

functions-framework==3.*

Der Code in der Datei main.py muss den Funktionseinstiegspunkt definieren und kann anderen Code und externe Abhängigkeiten wie gewohnt importieren. In der Datei main.py können auch mehrere Funktionseinstiegspunkte definiert werden, die separat bereitgestellt werden können.

Weitere Informationen finden Sie in der Python-Laufzeitübersicht und im Functions Framework für Python.

Go

Die grundlegende Verzeichnisstruktur für Go-Funktionen ist so:

.
├── myfunction.go
└── go.mod

Ihre Funktion muss sich in einem Go-Paket im Stammverzeichnis des Projekts befinden. Das Paket und seine Quelldateien können einen beliebigen Namen haben, aber Ihre Funktion darf sich nicht in package main befinden. Wenn Sie ein main-Paket benötigen, z. B. für lokale Tests, können Sie eines in einem Unterverzeichnis erstellen:

.
├── myfunction.go
├── go.mod
└── cmd/
  └── main.go

Die Datei go.mod muss das Functions Framework für Go als Abhängigkeit enthalten:

module example.com/my-module

require (
  github.com/GoogleCloudPlatform/functions-framework-go v1.5.2
)

Der Code im Root-Paket muss den Funktionseinstiegspunkt definieren und anderen Code aus Unterpaketen und Abhängigkeiten wie gewohnt importieren. Mit dem Paket können auch mehrere Funktionseinstiegspunkte definiert werden, die separat bereitgestellt werden können.

Weitere Informationen finden Sie in der Go-Laufzeitübersicht und im Functions Framework für Go.

Java

Die grundlegende Verzeichnisstruktur für Java-Funktionen sieht so aus:

.
├── pom.xml
└── src/
  └── main/
      └── java/
          └── MyFunction.java

Ihre Java-Quelldateien müssen sich im Verzeichnis src/main/java/ befinden und einen beliebigen Namen haben. Fügen Sie unter src/main/java ein zusätzliches Verzeichnis mit dem Namen des Pakets hinzu, wenn Ihre Quelldateien ein Paket deklarieren:

.
├── pom.xml
└── src/
  └── main/
      └── java/
          └── mypackage/
              └── MyFunction.java

Wir empfehlen, die zugehörigen Tests in einem Unterverzeichnis src/test/java/ abzulegen.

Die Datei pom.xml muss das Functions Framework für Java als Abhängigkeit enthalten:

...
    <dependency>
      <groupId>com.google.cloud.functions</groupId>
      <artifactId>functions-framework-api</artifactId>
      <version>1.0.4</version>
    </dependency>
...

Der Code in Ihren Quelldateien muss den Funktionseinstiegspunkt definieren und kann anderen Code und externe Abhängigkeiten wie gewohnt importieren. Mit Quelldateien können auch mehrere Funktionseinstiegspunkte definiert werden, die separat bereitgestellt werden können.

Weitere Informationen finden Sie unter Java-Laufzeit – Übersicht und Functions Framework für Java.

.NET

Die grundlegende Verzeichnisstruktur für .NET-Funktionen ist folgende:

.
├── MyFunction.cs
└── MyProject.csproj

Sie können Ihre Projekte wie jeden anderen .NET-Quellcode strukturieren. Ihre Quelldateien können einen beliebigen Namen haben.

Ihre Projektdatei muss das Functions Framework für .NET als Abhängigkeit enthalten:

...
    <PackageReference Include="Google.Cloud.Functions.Hosting" Version="1.0.0" />
...

Der Code in Ihren Quelldateien muss den Funktionseinstiegspunkt definieren und kann anderen Code und externe Abhängigkeiten wie gewohnt importieren. Mit Quelldateien können auch mehrere Funktionseinstiegspunkte definiert werden, die separat bereitgestellt werden können.

Weitere Informationen finden Sie in der Übersicht über die.NET-Laufzeit und im Functions Framework für .NET.

Ruby

Die grundlegende Verzeichnisstruktur für Ruby-Funktionen sieht so aus:

.
├── app.rb
├── Gemfile
└── Gemfile.lock

Cloud Run lädt den Quellcode aus einer Datei namens app.rb im Stammverzeichnis Ihres Funktionsverzeichnisses. Die Hauptdatei muss app.rb heißen.

Die Datei Gemfile muss das Functions Framework für Ruby als Abhängigkeit enthalten:

source "https://rubygems.org"
gem "functions_framework", "~> 1.0"

Der Code in der Datei app.rb muss den Funktionseinstiegspunkt definieren und kann anderen Code und externe Abhängigkeiten wie gewohnt importieren. In der Datei app.rb können auch mehrere Funktionseinstiegspunkte definiert werden, die separat bereitgestellt werden können.

Weitere Informationen finden Sie in der Übersicht über die Ruby-Laufzeit und im Functions Framework für Ruby.

PHP

Die grundlegende Verzeichnisstruktur für PHP-Funktionen sieht so aus:

.
├── index.php
└── composer.json

Cloud Run lädt den Quellcode aus einer Datei namens index.php im Stammverzeichnis Ihres Funktionsverzeichnisses. Die Hauptdatei muss index.php heißen.

Die Datei composer.json muss das Functions Framework für PHP als Abhängigkeit enthalten:

{
  "require": {
    "google/cloud-functions-framework": "^1.1"
  }
}

Der Code in der Datei index.php muss den Funktionseinstiegspunkt definieren und kann anderen Code und externe Abhängigkeiten wie gewohnt importieren. In der Datei index.php können auch mehrere Funktionseinstiegspunkte definiert werden, die separat bereitgestellt werden können.

Weitere Informationen finden Sie in der Übersicht: PHP-Laufzeit und im Functions Framework für PHP.

Wenn Sie mehrere Funktionen in einem Projekt gruppieren, beachten Sie, dass jede Funktion möglicherweise dieselben Abhängigkeiten verwendet. Einige der Funktionen benötigen jedoch möglicherweise nicht alle Abhängigkeiten.

Wir empfehlen, möglichst große Codefunktionen mit mehreren Funktionen aufzuteilen und jede Funktion wie in den vorherigen Beispielen gezeigt in einem eigenen Verzeichnis der obersten Ebene mit eigenen Quell- und Projektkonfigurationsdateien zu speichern. Dieser Ansatz minimiert die Anzahl der Abhängigkeiten, die für eine bestimmte Funktion erforderlich sind. Das reduziert wiederum den Speicherbedarf für Ihre Funktion.

HTTP-Funktionen schreiben

Sie schreiben eine HTTP-Funktion, wenn Sie eine Funktion über eine HTTP(S)-Anfrage aufrufen möchten. Um die HTTP-Semantik zu ermöglichen, verwenden Sie das Function Framework und geben die HTTP-Funktionssignatur an, um HTTP-spezifische Argumente zu akzeptieren.

Das folgende Beispiel zeigt eine einfache Quelldatei der HTTP-Funktion für jede Laufzeit. Ein vollständiges funktionierendes Beispiel finden Sie unter Cloud Run-Funktion mit der Google Cloud CLI bereitstellen. Weitere Informationen dazu, wo sich Ihr Quellcode befinden sollte, finden Sie unter Quellverzeichnisstruktur.

Node.js

ES-Modul

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

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

Fügen Sie der Datei package.json die folgenden Abhängigkeiten hinzu, einschließlich "type": "module":

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

CommonJS-Modul

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

Fügen Sie der Datei package.json die folgenden Abhängigkeiten hinzu:

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

In Node.js registrieren Sie eine HTTP-Handler-Funktion mit dem Functions Framework für Node.js. Ihre HTTP-Handler-Funktion muss eine Express-Middleware-Funktion sein, die die Anfrage- und Antwortargumente akzeptiert und eine HTTP-Antwort sendet.

Cloud Run parst den Anfragetext automatisch anhand des Content-Type-Headers der Anfrage mithilfe von body-parser, sodass Sie auf req.body und req.rawBody-Objekte im HTTP-Handler zugreifen können.

Der Funktionseinstiegspunkt ist der Name, mit dem der Handler beim Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt 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'

In Python registrieren Sie eine HTTP-Handler-Funktion mit dem Functions Framework für Python. Ihre HTTP-Handler-Funktion muss ein Flask-Anfrageobjekt als Argument akzeptieren und einen Wert zurückgeben, den Flask in ein HTTP-Antwortobjekt konvertieren kann.

Der Funktionseinstiegspunkt ist der Name, mit dem der Handler beim Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt 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")
}

In Go registrieren Sie eine HTTP-Handler-Funktion mit dem Functions Framework für Go in Ihrer init()-Funktion. Ihre HTTP-Handler-Funktion muss die Standardschnittstelle http.HandlerFunc verwenden, um eine HTTP-Antwort zu senden.

Der Funktionseinstiegspunkt ist der Name, mit dem der Handler beim Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt MyHTTPFunction.

Ihre HTTP-Handler-Funktion muss die Standardschnittstelle http.HandlerFunc implementieren. Sie akzeptiert eine http.ResponseWriter-Schnittstelle, mit der Ihre Funktion eine Antwort auf die Anfrage erstellt, und einen Zeiger auf eine http.Request-Struktur, die die Details der eingehenden HTTP-Anfrage enthält.

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

In Java verwenden Sie die Functions Framework Java API, um eine HTTP-Handler-Klasse mit der Schnittstelle HttpFunction zu implementieren. Die Methode service() muss eine HTTP-Antwort senden.

Der Funktionseinstiegspunkt ist der voll qualifizierte Name der HTTP-Handler-Klasse, einschließlich des Paketnamens. In diesem Beispiel ist der Einstiegspunkt myhttpfunction.MyHttpFunction.

Die Methode service empfängt ein HttpRequest-Objekt, das die eingehende HTTP-Anfrage beschreibt, und ein HttpResponse-Objekt, das von der Funktion mit einer Antwortnachricht ausgefüllt wird.

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

In .NET-Laufzeiten verwenden Sie das Functions Framework für .NET, um eine HTTP-Handler-Klasse mit der Benutzeroberfläche IHttpFunction. Die Methode HandleAsync() akzeptiert ein Standard-ASP.NET-Objekt HttpContext als Argument und muss eine HTTP-Antwort senden.

Der Funktionseinstiegspunkt ist der vollständig qualifizierte Name der HTTP-Handler-Klasse, einschließlich des Namespace. In diesem Beispiel ist der Einstiegspunkt 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

In Ruby registrieren Sie eine HTTP-Handler-Funktion mit dem Functions Framework für Ruby. Die HTTP-Handler-Funktion muss ein Rack-Anfrageobjekt als Argument akzeptieren und einen Wert zurückgeben, der als HTTP-Antwort verwendet werden kann.

Der Funktionseinstiegspunkt ist der Name, mit dem der Handler beim Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt 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';
}

In PHP registrieren Sie eine HTTP-Handler-Funktion mit dem Functions Framework für PHP. Ihre HTTP-Handler-Funktion muss ein Argument akzeptieren, das die PSR-7-Schnittstelle ServerRequestInterface implementiert, und muss eine HTTP-Antwort als String oder Objekt zurückgeben, das die PSR-7-Schnittstelle ResponseInterface implementiert.

Der Funktionseinstiegspunkt ist der Name, mit dem der Handler beim Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt myHttpFunction.

HTTP-Anfragen und ‑Antworten

Wenn Sie eine HTTP-Handler-Funktion mit dem Functions Framework registrieren, kann Ihr HTTP-Handler die Anfragemethode prüfen und je nach Methode verschiedene Aktionen ausführen.

Wenn Sie einen Ereignisanbieter so konfigurieren, dass er HTTP-Anfragen an Ihre Cloud Run-Funktion sendet, sendet Ihre Funktion eine HTTP-Antwort. Wenn die Funktion Hintergrundaufgaben erstellt (z. B. mit Threads, Futures, JavaScript-Promise-Objekten, -Callbacks oder Systemprozessen), müssen Sie diese Aufgaben vor dem Senden einer HTTP-Antwort beenden oder anderweitig auflösen. Alle Aufgaben, die vor dem Senden der HTTP-Antwort nicht beendet wurden, sind möglicherweise nicht abgeschlossen und können ein nicht definiertes Verhalten verursachen.

CORS verarbeiten

Mit Cross-Origin Resource Sharing (CORS) können Anwendungen, die auf einer Domain ausgeführt werden, auf Ressourcen einer anderen Domain zugreifen. Sie müssen beispielsweise zulassen können, dass Ihre Domain Anfragen an die Cloud Run Functions-Domain sendet, um auf Ihre Funktion zuzugreifen.

Setzen Sie den Header Access-Control-Allow-Origin entsprechend in Ihrer HTTP-Antwort, damit Cross-Origin-Anfragen an Ihre Funktion zugelassen werden. Bei Cross-Origin-Anfragen für Preflight-Anfragen müssen Sie auf die Preflight-Anfrage OPTIONS mit einem 204-Antwortcode und zusätzlichen Headern antworten.

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

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

Wenn CORS nicht richtig eingerichtet ist, werden möglicherweise folgende Fehler angezeigt:

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.

CORS-Einschränkungen

Bei Preflight-Origin-Anfragen werden Preflight-OPTIONS-Anfragen ohne Authorization-Header gesendet. Daher werden sie bei allen HTTP-Funktionen abgelehnt, die eine Authentifizierung erfordern. Da die Preflight-Anfragen fehlschlagen, schlägt auch die Hauptanfrage fehl. Verwenden Sie eine der folgenden Optionen, um diese Einschränkung zu umgehen:

Ereignisgesteuerte Funktionen schreiben

Schreiben Sie eine ereignisgesteuerte Funktion, wenn eine Funktion direkt als Reaktion auf Ereignisse in Ihrem Google Cloud Projekt ausgelöst werden soll, z. B. Nachrichten in einem Pub/Sub-Thema oder Änderungen in einem Cloud Storage-Bucket.

Ereignisgesteuerte Funktionen basieren auf CloudEvents, einer branchenweit üblichen Spezifikation zum allgemeinen Beschreiben von Ereignisdaten. Weitere Informationen zur CloudEvents-Spezifikation finden Sie im CloudEvents-GitHub-Repository. Das CloudEvents-Projekt bietet auch eine Reihe von CloudEvents SDKs, die Ihnen die Arbeit mit CloudEvents-Objekten in Ihrem Code erleichtern.

Das folgende Beispiel zeigt eine Quelldatei der ereignisgesteuerten Funktion für jede Laufzeit. Informationen zur Position Ihres Quellcodes finden Sie unter Quellverzeichnisstruktur.

Node.js

ES-Modul

  import { cloudEvent } from "@google-cloud/functions-framework";
  cloudEvent('myCloudEventFunction', cloudEvent => {
    // Your code here
    // Access the CloudEvent data payload using cloudEvent.data
  });

Fügen Sie der Datei package.json die folgenden Abhängigkeiten hinzu, einschließlich "type": "module":

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

CommonJS-Modul

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

// Register a CloudEvent function with the Functions Framework
functions.cloudEvent('myCloudEventFunction', cloudEvent => {
  // Your code here
  // Access the CloudEvent data payload using cloudEvent.data
});

Fügen Sie der Datei package.json die folgenden Abhängigkeiten hinzu:

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

In Node.js registrieren Sie eine CloudEvent-Handler-Funktion mit dem Functions Framework für Node.js. Ihre Handler-Funktion muss ein CloudEvent-Objekt als Argument akzeptieren.

Der Funktionseinstiegspunkt ist der Name, mit dem der Handler beim Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt myCloudEventFunction.

Python

import functions_framework

# Register a CloudEvent function with the Functions Framework
@functions_framework.cloud_event
def my_cloudevent_function(cloud_event):
  # Your code here
  # Access the CloudEvent data payload via cloud_event.data

In Python registrieren Sie eine CloudEvent-Handler-Funktion mit dem Functions Framework für Python. Ihre Handler-Funktion muss ein CloudEvent-Objekt als Argument akzeptieren.

Der Funktionseinstiegspunkt ist der Name der Handler-Funktion, die bei Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt my_cloudevent_function.

Go

package mycloudeventfunction

import (
    "context"

    "github.com/GoogleCloudPlatform/functions-framework-go/functions"
    "github.com/cloudevents/sdk-go/v2/event"
)

func init() {
    // Register a CloudEvent function with the Functions Framework
    functions.CloudEvent("MyCloudEventFunction", myCloudEventFunction)
}

// Function myCloudEventFunction accepts and handles a CloudEvent object
func myCloudEventFunction(ctx context.Context, e event.Event) error {
    // Your code here
    // Access the CloudEvent data payload using e.Data() or e.DataAs(...)

    // Returning an error causes its message to be logged.
    // Example:
    err := myInternalFunction() // may return an error
    if err != nil {
        // Append error message to log
        return err
    }

    // Return nil if no error occurred
    return nil
}

In Go registrieren Sie eine CloudEvent-Handler-Funktion mit dem Functions Framework für Go. Ihre Handler-Funktion muss eine CloudEvents event.Event Objekt akzeptieren als Argument.

Der Funktionseinstiegspunkt ist der Name, mit dem der Handler beim Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt MyCloudEventFunction.

Java

package mycloudeventfunction;

import com.google.cloud.functions.CloudEventsFunction;
import io.cloudevents.CloudEvent;

// Define a class that implements the CloudEventsFunction interface
public class MyCloudEventFunction implements CloudEventsFunction {
  // Implement the accept() method to handle CloudEvents
  @Override
  public void accept(CloudEvent event) {
    // Your code here
    // Access the CloudEvent data payload using event.getData()
    // To get the data payload as a JSON string, use:
    // new String(event.getData().toBytes())
  }
}

In Java verwenden Sie die Functions Framework Java API, um eine CloudEvent-Handler-Klasse mit der Schnittstelle CloudEventsFunction zu implementieren. Die Methode accept() muss ein CloudEvent-Objekt als Argument akzeptieren und alle erforderlichen Verarbeitungsschritte für das Ereignis ausführen.

Der Funktionseinstiegspunkt ist der voll qualifizierte Name der CloudEvent-Handler-Klasse, einschließlich des Paketnamens. In diesem Beispiel ist der Einstiegspunkt mycloudeventfunction.MyCloudEventFunction.

.NET

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using System.Threading;
using System.Threading.Tasks;

namespace MyProject
{
  // Define a class that implements the ICloudEventFunction<T> interface
  public class MyCloudEventFunction : ICloudEventFunction<CloudEventDataType>
  {
      // Implement the HandleAsync() method to handle CloudEvents
      public Task HandleAsync(CloudEvent cloudEvent, CloudEventDataType data, CancellationToken cancellationToken)
      {
          // Your code here
          // The data argument represents the CloudEvent data payload

          // Signal function completion
          return Task.CompletedTask;
      }
  }
}

In .NET-Laufzeiten verwenden Sie dasFunctions Framework für .NET So implementieren Sie eine CloudEvent-Handler-Klasse mit der ICloudEventFunction<T>-Schnittstelle. Die Methode HandleAsync() akzeptiert ein CloudEvent-Objekt und die zugehörige CloudEvent-Daten-Payload als Argumente.

Der Typ des CloudEvent-Datennutzlastarguments, der im Beispielcode als CloudEventDataType gezeigt wird, muss dem Typ des Ereignisses entsprechen, das von der Funktion verarbeitet wird. Die Google CloudEvents .NET-Bibliothek bietet Datentypen für die verschiedenen von Google unterstützten Ereignisse.

Der Funktionseinstiegspunkt ist der vollständig qualifizierte Name der CloudEvent-Handler-Klasse, einschließlich des Namespace. In diesem Beispiel ist der Einstiegspunkt MyProject.MyCloudEventFunction.

Ruby

require "functions_framework"

# Register a CloudEvent function with the Functions Framework
FunctionsFramework.cloud_event "my_cloudevent_function" do |cloud_event|
  # Your code here
  # Access the CloudEvent data payload via cloud_event.data
end

In Ruby registrieren Sie eine CloudEvent-Handler-Funktion mit dem Functions Framework für Ruby. Ihre Handler-Funktion muss eine CloudEvents Event Objekt akzeptieren als Argument.

Der Funktionseinstiegspunkt ist der Name, mit dem der Handler beim Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt my_cloudevent_function.

PHP

<?php

use CloudEvents\V1\CloudEventInterface;
use Google\CloudFunctions\FunctionsFramework;

// Register a CloudEvent function with the Functions Framework
FunctionsFramework::cloudEvent('myCloudEventFunction', 'myCloudEventHandler');

// Define your CloudEvent handler
function myCloudEventHandler(CloudEventInterface $event): void
{
    // Your code here
    // Access the CloudEvent data payload using $event->getData()
}

In PHP registrieren Sie eine CloudEvent-Handler-Funktion mit dem Functions Framework für PHP. Ihre Handler-Funktion muss ein Argument akzeptieren, das der Schnittstelle CloudEventInterface entspricht.

Der Funktionseinstiegspunkt ist der Name, mit dem der Handler beim Functions Framework registriert ist. In diesem Beispiel ist der Einstiegspunkt myCloudEventFunction.

Bei ereignisgesteuerten Funktionen werden Ereignisdaten im CloudEvents-Format an Ihre Funktion übergeben, wobei eine CloudEvent-Datennutzlast dem Ereignistyp entspricht, der Ihre Funktion auslöst. Informationen zu unterstützten Triggern, Ereignistypen und zugehörigen Ereignisdatenformaten finden Sie unter Funktionstrigger.

Das Repository Google Events enthält Ressourcen für die Arbeit mit CloudEvents, die herausgegeben von Google.

Beendigung der Funktion

Cloud Run betrachtet die ereignisgesteuerte Funktionsausführung als abgeschlossen, wenn die Funktion zurückgibt. Wenn die Funktion Hintergrundaufgaben erstellt (z. B. mit Threads, Futures, JavaScript-Promise-Objekten, -Callbacks oder Systemprozessen), müssen Sie diese Aufgaben beenden oder anderweitig auflösen, bevor Sie von Ihrer Funktion zurückgeben. Alle Aufgaben, die vor dem Zurückgeben durch die Funktion nicht beendet wurden, sind möglicherweise nicht abgeschlossen und können ein nicht definiertes Verhalten verursachen.

Automatische Wiederholungsversuche

Ereignisgesteuerte Funktionen können so konfiguriert werden, dass fehlgeschlagene Aufrufe automatisch wiederholt werden. Weitere Informationen finden Sie unter Ereignisgesteuerte Funktionen wiederholen.

Nächste Schritte