创建推送订阅

本文档介绍如何创建推送订阅。您可以使用 Google Cloud 控制台、Google Cloud CLI、客户端库或 Pub/Sub API 来创建推送订阅。

准备工作

所需的角色和权限

如需创建订阅,您必须在项目级别配置访问权限控制。如果您的订阅和主题位于不同的项目中,则还需要资源级权限,如本部分稍后所述。

如需获取创建推送订阅所需的权限,请让管理员授予您项目的 Pub/Sub Editor (roles/pubsub.editor) IAM 角色。如需详细了解如何授予角色,请参阅管理访问权限

此预定义角色包含创建推送订阅所需的权限。如需查看所需的确切权限,请展开所需权限部分:

所需权限

如需创建推送订阅,您必须拥有以下权限:

  • 创建订阅: pubsub.subscriptions.create
  • 删除订阅: pubsub.subscriptions.delete
  • 获取订阅: pubsub.subscriptions.get
  • 列出订阅: pubsub.subscriptions.list
  • 更新订阅: pubsub.subscriptions.update
  • 将订阅附加到主题: pubsub.topics.attachSubscription
  • 获取订阅的 IAM 政策: pubsub.subscriptions.getIamPolicy
  • 为订阅配置 IAM 政策 pubsub.subscriptions.setIamPolicy

您也可以使用自定义角色或其他预定义角色来获取这些权限。

如果您需要在一个与另一个项目中的主题相关联的项目中创建推送订阅,请让主题管理员也向您授予该主题的 Pub/Sub Editor (roles/pubsub.editor) IAM 角色。

推送订阅属性

配置推送订阅时,您可以指定以下属性。

通用属性

了解您可以为所有订阅设置的常见订阅属性

端点

端点网址(必填)。可公开访问的 HTTPS 地址。推送端点的服务器必须具有由证书授权机构签名的有效 SSL 证书。Pub/Sub 服务会将同一 Google Cloud 地区中的消息传送至 Pub/Sub 服务存储消息所在的推送端点。Pub/Sub 服务会尽最大努力传送来自同一 Google Cloud 地区的消息。

Pub/Sub 不再要求推送订阅网址网域的所有权证明。如果您的网域收到来自 Pub/Sub 的意外 POST 请求,您可以举报疑似滥用行为

Authentication

启用身份验证。启用后,Pub/Sub 传送到推送端点的消息将包含授权标头,以允许端点对请求进行身份验证。自动身份验证和授权机制适用于与订阅位于同一项目中的 App Engine 标准环境和 Cloud Functions 端点。

经过身份验证的推送订阅的身份验证配置由用户代管式服务帐号以及在 createpatchModifyPushConfig 调用中指定的受众群体参数。您还必须为特殊的 Google 代管式服务帐号授予特定角色,如下一部分所述。

  • 代管式服务帐号(必需)。与推送订阅关联的服务帐号。此帐号用作生成的 JSON 网络令牌 (JWT) 的 email 声明。以下是服务帐号的要求列表:

  • 受众群体 -一个不区分大小写的字符串,webhook 用于验证此特定令牌的目标受众群体。

  • Google 代管式服务帐号(必需)。

    • Pub/Sub 会自动为您创建格式为 service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com 的服务帐号。

    • 必须为此服务帐号授予 iam.serviceAccounts.getOpenIdToken 权限(包含在 roles/iam.serviceAccountTokenCreator 角色中),这样 Pub/Sub 才能为经过身份验证的推送请求创建 JWT 令牌。

载荷解封

启用载荷解封选项会去除所有消息元数据(消息数据除外)的 Pub/Sub 消息。通过载荷解封,消息数据将直接作为 HTTP 正文传送。

  • 写入元数据。将之前移除的消息元数据添加回请求标头中。

VPC Service Controls

对于受 VPC Service Controls 保护的项目,请注意推送订阅的以下限制:

  • 您只能创建推送端点设置为具有默认 run.app 网址或 Workflows 执行的 Cloud Run 服务的新推送订阅。自定义网域不起作用。

  • 通过 Eventarc 将事件路由到推送端点设置为 Workflows 执行的 Workflows 目的地时,您只能通过 Eventarc 创建新的推送订阅。

  • 您无法更新现有的推送订阅。虽然这些推送订阅不受 VPC Service Controls 的保护,但仍将继续运行。

创建推送订阅

以下示例演示了如何使用提供的默认设置创建采用推送传送的订阅。

默认情况下,订阅使用拉取传送,除非您明确设置推送配置,如以下示例所示。

控制台

如需创建推送订阅,请完成以下步骤:

  1. 在 Google Cloud 控制台中,前往订阅页面。

    前往“订阅”页面

  2. 点击创建订阅
  3. 订阅 ID 字段中,输入一个名称。

    如需了解如何为订阅命名,请参阅主题或订阅命名准则

  4. 从下拉菜单中选择或创建一个主题。订阅将接收来自该主题的消息。
  5. 传送类型中选择推送
  6. 指定端点网址。
  7. 保留所有其他默认值。
  8. 点击创建

您还可以通过主题部分创建订阅。此快捷方式可帮助您将主题与订阅关联。

  1. 在 Google Cloud 控制台中,前往主题页面。

    转到“主题”

  2. 点击要创建订阅的主题旁边的
  3. 从上下文菜单中,选择创建订阅
  4. 输入订阅 ID

    如需了解如何为订阅命名,请参阅主题或订阅命名准则

  5. 传送类型中选择推送
  6. 指定端点网址。
  7. 保留所有其他默认值。
  8. 点击创建

gcloud

  1. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

    Cloud Shell 会话随即会在 Google Cloud 控制台的底部启动,并显示命令行提示符。Cloud Shell 是一个已安装 Google Cloud CLI 且已为当前项目设置值的 Shell 环境。该会话可能需要几秒钟时间来完成初始化。

  2. 如需创建推送订阅,请运行 gcloud pubsub subscriptions create 命令。

    gcloud pubsub subscriptions create SUBSCRIPTION_ID \
        --topic=TOPIC_ID \
        --push-endpoint=PUSH_ENDPOINT

    替换以下内容:

    • SUBSCRIPTION_ID:新推送订阅的名称或 ID。
    • TOPIC_ID:主题的名称或 ID。
    • PUSH_ENDPOINT:要用作此订阅的端点的网址。例如 https://myproject.appspot.com/myhandler

REST

如需创建推送订阅,请使用 projects.subscriptions.create 方法:

请求:

必须使用 Authorization 标头中的访问令牌对请求进行身份验证。如需获取当前应用默认凭据的访问令牌,请运行以下命令:gcloud auth application-default print-access-token

PUT https://pubsub.googleapis.com/v1/projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID
Authorization: Bearer ACCESS_TOKEN

请求正文:

{
  "topic": "projects/PROJECT_ID/topics/TOPIC_ID",
  // Only needed if you are using push delivery
  "pushConfig": {
    "pushEndpoint": "PUSH_ENDPOINT"
  }
}

其中:

  • PROJECT_ID 是项目 ID。
  • SUBSCRIPTION_ID 是您的订阅 ID。
  • TOPIC_ID 是主题 ID。
  • PUSH_ENDPOINT 是要用作端点的网址。例如 https://myproject.appspot.com/myhandler
  • 响应:

    {
      "name": "projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID",
      "topic": "projects/PROJECT_ID/topics/TOPIC_ID",
      "pushConfig": {
        "pushEndpoint": "https://PROJECT_ID.appspot.com/myhandler",
        "attributes": {
          "x-goog-version": "v1"
        }
      },
      "ackDeadlineSeconds": 10,
      "messageRetentionDuration": "604800s",
      "expirationPolicy": {
        "ttl": "2678400s"
      }
    }
    

    C++

    在尝试此示例之前,请按照《快速入门:使用客户端库》中的 C++ 设置说明进行操作。如需了解详情,请参阅 Pub/Sub C++ API 参考文档

    namespace pubsub = ::google::cloud::pubsub;
    namespace pubsub_admin = ::google::cloud::pubsub_admin;
    [](pubsub_admin::SubscriptionAdminClient client,
       std::string const& project_id, std::string const& topic_id,
       std::string const& subscription_id, std::string const& endpoint) {
      google::pubsub::v1::Subscription request;
      request.set_name(
          pubsub::Subscription(project_id, subscription_id).FullName());
      request.set_topic(pubsub::Topic(project_id, topic_id).FullName());
      request.mutable_push_config()->set_push_endpoint(endpoint);
      auto sub = client.CreateSubscription(request);
      if (sub.status().code() == google::cloud::StatusCode::kAlreadyExists) {
        std::cout << "The subscription already exists\n";
        return;
      }
      if (!sub) throw std::move(sub).status();
    
      std::cout << "The subscription was successfully created: "
                << sub->DebugString() << "\n";

    C#

    在试用此示例之前,请按照 Pub/Sub 快速入门:使用客户端库中的 C# 设置说明进行操作。如需了解详情,请参阅 Pub/Sub C# API 参考文档

    要向 Pub/Sub 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为客户端库设置身份验证

    
    using Google.Cloud.PubSub.V1;
    
    public class CreatePushSubscriptionSample
    {
        public Subscription CreatePushSubscription(string projectId, string topicId, string subscriptionId, string pushEndpoint)
        {
            SubscriberServiceApiClient subscriber = SubscriberServiceApiClient.Create();
            TopicName topicName = TopicName.FromProjectTopic(projectId, topicId);
            SubscriptionName subscriptionName = SubscriptionName.FromProjectSubscription(projectId, subscriptionId);
    
            PushConfig pushConfig = new PushConfig { PushEndpoint = pushEndpoint };
    
            // The approximate amount of time in seconds (on a best-effort basis) Pub/Sub waits for the
            // subscriber to acknowledge receipt before resending the message.
            var ackDeadlineSeconds = 60;
            var subscription = subscriber.CreateSubscription(subscriptionName, topicName, pushConfig, ackDeadlineSeconds);
            return subscription;
        }
    }

    Go

    在试用此示例之前,请按照 Pub/Sub 快速入门:使用客户端库中的 Go 设置说明进行操作。如需了解详情,请参阅 Pub/Sub Go API 参考文档

    要向 Pub/Sub 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为客户端库设置身份验证

    import (
    	"context"
    	"fmt"
    	"io"
    	"time"
    
    	"cloud.google.com/go/pubsub"
    )
    
    func createWithEndpoint(w io.Writer, projectID, subID string, topic *pubsub.Topic, endpoint string) error {
    	// projectID := "my-project-id"
    	// subID := "my-sub"
    	// topic of type https://godoc.org/cloud.google.com/go/pubsub#Topic
    	// endpoint := "https://my-test-project.appspot.com/push"
    	ctx := context.Background()
    	client, err := pubsub.NewClient(ctx, projectID)
    	if err != nil {
    		return fmt.Errorf("pubsub.NewClient: %w", err)
    	}
    	defer client.Close()
    
    	sub, err := client.CreateSubscription(ctx, subID, pubsub.SubscriptionConfig{
    		Topic:       topic,
    		AckDeadline: 10 * time.Second,
    		PushConfig:  pubsub.PushConfig{Endpoint: endpoint},
    	})
    	if err != nil {
    		return fmt.Errorf("CreateSubscription: %w", err)
    	}
    	fmt.Fprintf(w, "Created push subscription: %v\n", sub)
    	return nil
    }
    

    Java

    在试用此示例之前,请按照 Pub/Sub 快速入门:使用客户端库中的 Java 设置说明进行操作。如需了解详情,请参阅 Pub/Sub Java API 参考文档

    要向 Pub/Sub 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为客户端库设置身份验证

    
    import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
    import com.google.pubsub.v1.PushConfig;
    import com.google.pubsub.v1.Subscription;
    import com.google.pubsub.v1.SubscriptionName;
    import com.google.pubsub.v1.TopicName;
    import java.io.IOException;
    
    public class CreatePushSubscriptionExample {
      public static void main(String... args) throws Exception {
        // TODO(developer): Replace these variables before running the sample.
        String projectId = "your-project-id";
        String subscriptionId = "your-subscription-id";
        String topicId = "your-topic-id";
        String pushEndpoint = "https://my-test-project.appspot.com/push";
    
        createPushSubscriptionExample(projectId, subscriptionId, topicId, pushEndpoint);
      }
    
      public static void createPushSubscriptionExample(
          String projectId, String subscriptionId, String topicId, String pushEndpoint)
          throws IOException {
        try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) {
          TopicName topicName = TopicName.of(projectId, topicId);
          SubscriptionName subscriptionName = SubscriptionName.of(projectId, subscriptionId);
          PushConfig pushConfig = PushConfig.newBuilder().setPushEndpoint(pushEndpoint).build();
    
          // Create a push subscription with default acknowledgement deadline of 10 seconds.
          // Messages not successfully acknowledged within 10 seconds will get resent by the server.
          Subscription subscription =
              subscriptionAdminClient.createSubscription(subscriptionName, topicName, pushConfig, 10);
          System.out.println("Created push subscription: " + subscription.getName());
        }
      }
    }

    Node.js

    /**
     * TODO(developer): Uncomment these variables before running the sample.
     */
    // const pushEndpoint = 'YOUR_ENDPOINT_URL';
    // const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
    // const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';
    
    // Imports the Google Cloud client library
    const {PubSub} = require('@google-cloud/pubsub');
    
    // Creates a client; cache this for further use
    const pubSubClient = new PubSub();
    
    async function createPushSubscription(
      pushEndpoint,
      topicNameOrId,
      subscriptionNameOrId
    ) {
      const options = {
        pushConfig: {
          // Set to an HTTPS endpoint of your choice. If necessary, register
          // (authorize) the domain on which the server is hosted.
          pushEndpoint,
        },
      };
    
      await pubSubClient
        .topic(topicNameOrId)
        .createSubscription(subscriptionNameOrId, options);
      console.log(`Subscription ${subscriptionNameOrId} created.`);
    }

    Node.js

    /**
     * TODO(developer): Uncomment these variables before running the sample.
     */
    // const pushEndpoint = 'YOUR_ENDPOINT_URL';
    // const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
    // const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';
    
    // Imports the Google Cloud client library
    import {PubSub, CreateSubscriptionOptions} from '@google-cloud/pubsub';
    
    // Creates a client; cache this for further use
    const pubSubClient = new PubSub();
    
    async function createPushSubscription(
      pushEndpoint: string,
      topicNameOrId: string,
      subscriptionNameOrId: string
    ) {
      const options: CreateSubscriptionOptions = {
        pushConfig: {
          // Set to an HTTPS endpoint of your choice. If necessary, register
          // (authorize) the domain on which the server is hosted.
          pushEndpoint,
        },
      };
    
      await pubSubClient
        .topic(topicNameOrId)
        .createSubscription(subscriptionNameOrId, options);
      console.log(`Subscription ${subscriptionNameOrId} created.`);
    }

    PHP

    在试用此示例之前,请按照 Pub/Sub 快速入门:使用客户端库中的 PHP 设置说明进行操作。如需了解详情,请参阅 Pub/Sub PHP API 参考文档

    要向 Pub/Sub 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为客户端库设置身份验证

    use Google\Cloud\PubSub\PubSubClient;
    
    /**
     * Creates a Pub/Sub push subscription.
     *
     * @param string $projectId  The Google project ID.
     * @param string $topicName  The Pub/Sub topic name.
     * @param string $subscriptionName  The Pub/Sub subscription name.
     * @param string $endpoint  The endpoint for the push subscription.
     */
    function create_push_subscription($projectId, $topicName, $subscriptionName, $endpoint)
    {
        $pubsub = new PubSubClient([
            'projectId' => $projectId,
        ]);
        $topic = $pubsub->topic($topicName);
        $subscription = $topic->subscription($subscriptionName);
        $subscription->create([
            'pushConfig' => ['pushEndpoint' => $endpoint]
        ]);
    
        printf('Subscription created: %s' . PHP_EOL, $subscription->name());
    }

    Python

    在试用此示例之前,请按照 Pub/Sub 快速入门:使用客户端库中的 Python 设置说明进行操作。如需了解详情,请参阅 Pub/Sub Python API 参考文档

    要向 Pub/Sub 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为客户端库设置身份验证

    from google.cloud import pubsub_v1
    
    # TODO(developer)
    # project_id = "your-project-id"
    # topic_id = "your-topic-id"
    # subscription_id = "your-subscription-id"
    # endpoint = "https://my-test-project.appspot.com/push"
    
    publisher = pubsub_v1.PublisherClient()
    subscriber = pubsub_v1.SubscriberClient()
    topic_path = publisher.topic_path(project_id, topic_id)
    subscription_path = subscriber.subscription_path(project_id, subscription_id)
    
    push_config = pubsub_v1.types.PushConfig(push_endpoint=endpoint)
    
    # Wrap the subscriber in a 'with' block to automatically call close() to
    # close the underlying gRPC channel when done.
    with subscriber:
        subscription = subscriber.create_subscription(
            request={
                "name": subscription_path,
                "topic": topic_path,
                "push_config": push_config,
            }
        )
    
    print(f"Push subscription created: {subscription}.")
    print(f"Endpoint for subscription is: {endpoint}")

    Ruby

    在试用此示例之前,请按照 Pub/Sub 快速入门:使用客户端库中的 Ruby 设置说明进行操作。如需了解详情,请参阅 Pub/Sub Ruby API 参考文档

    要向 Pub/Sub 进行身份验证,请设置应用默认凭据。如需了解详情,请参阅为客户端库设置身份验证

    # topic_id          = "your-topic-id"
    # subscription_id   = "your-subscription-id"
    # endpoint          = "https://your-test-project.appspot.com/push"
    
    pubsub = Google::Cloud::Pubsub.new
    
    topic        = pubsub.topic topic_id
    subscription = topic.subscribe subscription_id,
                                   endpoint: endpoint
    
    puts "Push subscription #{subscription_id} created."

    后续步骤