編寫 HTTP 函式

在 Cloud Run 函式中,如要透過 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 中,您可以使用 Node.js 適用的 Functions Framework 註冊 HTTP 處理常式函式。HTTP 處理常式函式必須是 Express 中介軟體函式,可接受要求回應引數,並傳送 HTTP 回應。

Cloud Run functions 會根據要求的 Content-Type 標頭,使用 body-parser 自動剖析要求主體,因此您可以在 HTTP 處理常式中存取 req.bodyreq.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 中,您可以使用 Python 適用的 Functions Framework 註冊 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 中,您可以在 init() 函式中,使用 Go 適用的 Functions Framework 註冊 HTTP 處理常式函式。HTTP 處理常式函式必須使用標準 http.HandlerFunc 介面傳送 HTTP 回應。

函式進入點是處理常式向 Functions Framework 註冊的名稱。在本範例中,進入點為 MyHTTPFunction

HTTP 處理常式函式必須實作標準的 http.HandlerFunc 介面。這個函式會接受 http.ResponseWriter 介面,您的函式會使用這個介面建立要求的回覆,以及指向 http.Request 結構的指標,其中包含傳入 HTTP 要求的詳細資料。

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 方法會收到 HttpRequest 物件,其中說明傳入的 HTTP 要求,以及 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 執行階段中,您可以使用 .NET 適用的 Functions Framework,透過 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 中,您可以使用 Ruby 適用的 Functions Framework 註冊 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 中,您可以使用 PHP 適用的 Functions Framework 註冊 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 函式網域提出要求,才能存取函式。

如果 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 函式中遭到拒絕。由於預檢要求失敗,主要要求也會失敗。如要避開這項限制,請採取下列任一做法:

後續步驟