HTTP 関数を作成する

Cloud Run functions では、HTTP(S) リクエストを介して関数を呼び出す必要のある場合に HTTP 関数を使用します。HTTP セマンティクスを実行するため、HTTP 関数シグネチャは HTTP 固有の引数を受け入れます。

実装

以下に、各ランタイムの基本的な HTTP 関数のソースファイルを示します。ソースコードの場所については、ソース ディレクトリ構造をご覧ください。

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

Node.js で Functions Framework for Node.js を使用して、HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、リクエストレスポンスの引数を受け入れて HTTP レスポンスを送信する Express ミドルウェア関数である必要があります。

Cloud Run functions では、body-parser を使用して、リクエストの Content-Type ヘッダーに基づいてリクエスト本文を自動的に解析するため、HTTP ハンドラ内の req.body または req.rawBody オブジェクトにアクセスできます。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは 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'

Python で、Functions Framework for Python を使用して HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、Flask リクエストのオブジェクトを引数として受け取り、Flask が HTTP レスポンス オブジェクトに変換可能な値を返す必要があります。

関数のエントリ ポイントは、Functions Framework に登録されたハンドラ関数の名前です。この例では、エントリ ポイントは 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")
}

Go で、Functions Framework for Go を使用して init() 関数で HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、標準の http.HandlerFunc インターフェースを使用して HTTP レスポンスを送信する必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは MyHTTPFunction です。

HTTP ハンドラ関数は、標準の http.HandlerFunc インターフェースを実装する必要があります。関数がリクエストへの応答を作成するために使用する http.ResponseWriter インターフェースと、インバウンド HTTP リクエストの詳細情報を含む http.Request 構造体へのポインタを受け入れます。

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

Java では、Functions Framework Java API を使用して、HttpFunction インターフェースを持つ HTTP ハンドラクラスを実装します。service() メソッドは HTTP レスポンスを送信する必要があります。

関数のエントリ ポイントは、HTTP ハンドラクラスの完全修飾名(パッケージ名を含む)です。この例では、エントリ ポイントは myhttpfunction.MyHttpFunction です。

service メソッドは、受信 HTTP リクエストを記述する HttpRequest オブジェクトと、関数によってレスポンス メッセージが設定される HttpResponse オブジェクトを受け取ります。

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

.NET ランタイムで、Functions Framework for .NET を使用して、IHttpFunction インターフェースを持つ HTTP ハンドラクラスを実装します。HandleAsync() メソッドは、標準の ASP.NET HttpContext オブジェクトを引数として受け取り、HTTP レスポンスを送信する必要があります。

関数のエントリ ポイントは、HTTP ハンドラクラスの完全修飾名(名前空間を含む)です。この例では、エントリ ポイントは 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

Ruby では、Functions Framework for Ruby を使用して HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、Rack リクエスト オブジェクトを引数として受け取り、HTTP レスポンスとして使用可能な値を返す必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは 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';
}

PHP で、Functions Framework for PHP を使用して HTTP ハンドラ関数を登録します。HTTP ハンドラ関数は、PSR-7 ServerRequestInterface インターフェースを実装する引数を受け取り、文字列または PSR-7 ResponseInterface インターフェースを実装するオブジェクトとして HTTP レスポンスを返す必要があります。

関数のエントリ ポイントは、ハンドラを Functions Framework に登録したときに使用した名前です。この例では、エントリ ポイントは myHttpFunction です。

HTTP リクエストとレスポンス

HTTP 関数は、HTTP トリガーページにある HTTP リクエスト メソッドを受け入れます。HTTP ハンドラは、リクエスト メソッドを検査し、メソッドに応じてさまざまなアクションを実行できます。

関数は、HTTP レスポンスを送信する必要があります。関数によってバックグラウンド タスク(スレッド、Future、JavaScript Promise オブジェクト、コールバック、システム プロセスなど)が作成される場合は、HTTP レスポンスが送信される前に、これらのタスクを終了します。あるいは、他の方法で問題を解決する必要があります。HTTP レスポンスが送信される前に終了しなかったタスクは完了しません。未定義の動作が行われる可能性があります。

HTTP 関数とそれに関連するオプションの詳細については、HTTP トリガーをご覧ください。

CORS の処理

クロスオリジン リソース シェアリング(CORS)は、あるドメインで実行されているアプリケーションが別のドメインのリソースにアクセスできるようにする方法です。たとえば、関数にアクセスするために、ドメインから Cloud Run functions のドメインへのリクエストを許可する必要があるとします。

CORS が正しく設定されていないと、次のようなエラーが表示されることがあります。

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.

関数に対するクロスオリジン リクエストを許可するには、HTTP レスポンスに適切な Access-Control-Allow-Origin ヘッダーを設定します。プリフライトされたクロスオリジン リクエストの場合、204 レスポンス コードと追加のヘッダーを使用して、プリフライトの OPTIONS リクエストに応答する必要があります。

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

CORS の制限

プリフライトされたクロスオリジン リクエストの場合、プリフライトの OPTIONS リクエストは Authorization ヘッダーなしで送信されるため、認証が必要なすべての HTTP 関数でリクエストが拒否されます。プリフライト リクエストが失敗するため、メイン リクエストも失敗します。この制限を回避するには、次のいずれかのオプションを使用します。

次のステップ