Écrire des fonctions HTTP

Dans Cloud Run Functions, vous utilisez des fonctions HTTP lorsque vous souhaitez appeler une fonction via une requête HTTP(S). Pour autoriser la sémantique HTTP, les signatures de fonction HTTP acceptent des arguments HTTP spécifiques.

Implémentation

L'exemple suivant montre un fichier source de fonction HTTP de base pour chaque environnement d'exécution. Consultez la section Structure du répertoire source pour savoir où trouver votre code source.

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

Avec Node.js, vous enregistrez une fonction de gestionnaire HTTP avec le framework des fonctions pour Node.js. Votre fonction de gestionnaire HTTP doit être une fonction du middleware Express qui accepte les arguments de requête et de réponse et envoie une réponse HTTP.

Cloud Run Functions analyse automatiquement le corps de la requête en fonction de son en-tête Content-Type à l'aide de body-parser. Vous pouvez ainsi accéder aux objets req.body et req.rawBody dans votre gestionnaire HTTP.

Le point d'entrée de la fonction est le nom auprès duquel le gestionnaire est enregistré dans le framework des fonctions. Dans cet exemple, le point d'entrée est 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'

Avec Python, vous enregistrez une fonction de gestionnaire HTTP avec le framework des fonctions pour Python. Votre fonction de gestionnaire HTTP doit accepter un objet de requête Flask en tant qu'argument et renvoyer une valeur que Flask peut convertir en objet de réponse HTTP.

Le point d'entrée de la fonction est le nom de la fonction de gestionnaire enregistrée avec le framework des fonctions. Dans cet exemple, le point d'entrée est 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")
}

Avec Go, vous enregistrez une fonction de gestionnaire HTTP avec le framework des fonctions pour Go dans votre fonction init(). Votre fonction de gestionnaire HTTP doit utiliser l'interface http.HandlerFunc standard pour envoyer une réponse HTTP.

Le point d'entrée de la fonction est le nom auprès duquel le gestionnaire est enregistré dans le framework des fonctions. Dans cet exemple, le point d'entrée est MyHTTPFunction.

Votre fonction de gestionnaire HTTP doit mettre en œuvre l'interface http.HandlerFunc standard. Elle accepte une interface http.ResponseWriter utilisée par votre fonction pour créer une réponse à la requête, et un pointeur vers une structure http.Request contenant les détails de la requête 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, vous utilisez l'API Java du framework des fonctions pour mettre en œuvre une classe de gestionnaire HTTP avec l'interface HttpFunction. La méthode service() doit envoyer une réponse HTTP.

Le point d'entrée de la fonction est le nom complet de la classe de gestionnaire HTTP, y compris le nom du package. Dans cet exemple, le point d'entrée est myhttpfunction.MyHttpFunction.

Votre méthode service reçoit un objet HttpRequest décrivant la requête HTTP entrante et un objet HttpResponse que votre fonction renseigne avec un message de réponse.

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

Dans les environnements d'exécution .NET, vous utilisez le framework des fonctions pour .NET pour mettre en œuvre une classe de gestionnaire HTTP avec l'interface IHttpFunction. La méthode HandleAsync() accepte un objet ASP.NET HttpContext standard en tant qu'argument et doit envoyer une réponse HTTP.

Le point d'entrée de la fonction est le nom complet de la classe de gestionnaire HTTP, y compris l'espace de noms. Dans cet exemple, le point d'entrée est 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

Avec Ruby, vous enregistrez une fonction de gestionnaire HTTP avec le framework des fonctions pour Ruby. Votre fonction de gestionnaire HTTP doit accepter un objet de requête Rack en tant qu'argument et renvoyer une valeur pouvant être utilisée comme réponse HTTP.

Le point d'entrée de la fonction est le nom auprès duquel le gestionnaire est enregistré dans le framework des fonctions. Dans cet exemple, le point d'entrée est 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';
}

Avec PHP, vous enregistrez une fonction de gestionnaire HTTP avec le framework des fonctions pour PHP. Votre fonction de gestionnaire HTTP doit accepter un argument qui met en œuvre l'interface PSR-7 ServerRequestInterface, et doit renvoyer une réponse HTTP sous forme de chaîne ou d'objet qui met en œuvre l'interface PSR-7 ResponseInterface.

Le point d'entrée de la fonction est le nom auprès duquel le gestionnaire est enregistré dans le framework des fonctions. Dans cet exemple, le point d'entrée est myHttpFunction.

Requêtes et réponses HTTP

Les fonctions HTTP acceptent les méthodes de requête HTTP répertoriées sur la page Déclencheurs HTTP. Votre gestionnaire HTTP peut inspecter la méthode de requête et effectuer différentes actions en fonction de la méthode.

Votre fonction doit envoyer une réponse HTTP. Si la fonction crée des tâches en arrière-plan (par exemple, des threads, des futurs, des objets Promise JavaScript, des rappels ou des processus système), vous devez arrêter ou résoudre ces tâches avant d'envoyer une réponse HTTP. Toute tâche qui n'est pas arrêtée avant l'envoi de la réponse HTTP peut ne pas être terminée et peut entraîner un comportement indéfini.

Pour en savoir plus sur les fonctions HTTP et les options associées, consultez la page Déclencheurs HTTP.

Gérer le CORS

Le mécanisme Cross-Origin Resource Sharing (CORS) permet aux applications exécutées sur un domaine d'accéder aux ressources d'un autre domaine. Par exemple, vous devrez peut-être autoriser votre domaine à envoyer des requêtes au domaine Cloud Run Functions pour accéder à votre fonction.

Si le CORS n'est pas configuré correctement, vous pouvez rencontrer des erreurs de ce type :

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.

Pour autoriser les requêtes multi-origines sur votre fonction, définissez l'en-tête Access-Control-Allow-Origin de manière appropriée dans votre réponse HTTP. Pour les requêtes inter-origines préliminaires, vous devez répondre à la requête OPTIONS préliminaire avec un code de réponse 204 et des en-têtes supplémentaires.

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

Limites du CORS

Pour les requêtes inter-origines préliminaires, les requêtes OPTIONS préliminaires sont envoyées sans en-tête Authorization. Elles seront donc refusées pour toutes les fonctions HTTP nécessitant une authentification. Comme les requêtes préliminaires échouent, les requêtes principales échoueront également. Pour contourner cette limitation, utilisez l'une des options suivantes :

Étapes suivantes