編寫 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 中介層函式,可接受 requestresponse 引數,並傳送 HTTP 回應。

Cloud Run 函式會使用 body-parser,根據要求的 Content-Type 標頭自動剖析要求主體,讓您可以在 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 方法會接收描述傳入 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 執行階段中,您可以使用 .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 回應。如果函式建立背景工作 (例如使用執行緒、未來、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 函式中遭到拒絕。由於預先檢查要求失敗,因此主要要求也會失敗。如要突破這項限制,請使用下列任一選項:

後續步驟