编写 HTTP 函数

在 Cloud 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 中,您可以向 Node.js 版 Functions 框架注册 HTTP 处理程序函数。HTTP 处理程序函数必须是 Express 中间件函数,该函数会接受请求响应参数并发送 HTTP 响应。

Cloud Functions 使用 body-parser 根据请求的 Content-Type 标头为您自动解析请求正文,因此您可以在 HTTP 处理程序中访问 req.bodyreq.rawBody 对象。

函数入口点是向 Functions 框架注册处理程序时使用的名称。在此示例中,入口点为 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 框架注册 HTTP 处理程序函数。HTTP 处理程序函数必须接受 Flask 请求对象作为参数,并返回 Flask 可以将其转换为 HTTP 响应对象的值

函数入口点是向 Functions 框架注册的处理程序函数的名称。在此示例中,入口点为 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 框架注册 HTTP 处理程序函数。HTTP 处理程序函数必须使用标准 http.HandlerFunc 接口发送 HTTP 响应。

函数入口点是向 Functions 框架注册处理程序时使用的名称。在此示例中,入口点为 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 运行时中,您可以使用 .NET 版 Functions 框架 通过 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 框架注册 HTTP 处理程序函数。HTTP 处理程序函数必须接受 Rack 请求对象作为参数,并返回可用作 HTTP 响应的值

函数入口点是向 Functions 框架注册处理程序时使用的名称。在此示例中,入口点为 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 框架注册 HTTP 处理程序函数。HTTP 处理程序函数必须接受实现 PSR-7 ServerRequestInterface 接口的参数,并且必须以字符串或对象形式返回 HTTP 响应以实现 PSR-7 ResponseInterface 接口。

函数入口点是向 Functions 框架注册处理程序时使用的名称。在此示例中,入口点为 myHttpFunction

HTTP 请求和响应

HTTP 函数接受 HTTP 触发器页面上列出的 HTTP 请求方法。HTTP 处理程序可以检查请求方法,并根据该方法执行不同的操作。

您的函数必须发送 HTTP 响应。如果函数创建了后台任务(例如使用线程、future、JavaScript Promise 对象、回调或系统进程),则必须先终止这些任务或以其他方式对其进行解析,然后再发送 HTTP 响应。在 HTTP 响应发送之前未终止的任何任务都可能无法完成,并且可能导致未定义的行为。

如需详细了解 HTTP 函数和相关选项,请参阅 HTTP 触发器

处理 CORS

跨域资源共享 (CORS) 的作用是让一个网域上运行的应用访问另一网域中的资源。例如,您可能需要让您的网域向 Cloud 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!");
    }
}

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 函数上,这些请求会被拒绝。由于预检请求失败,因此主请求也将失败。要突破此限制,请使用以下选项之一:

后续步骤