Como gravar e responder mensagens do Pub/Sub

ID da região

O REGION_ID é um código abreviado que o Google atribui com base na região que você selecionou ao criar o aplicativo. O código não corresponde a um país ou estado, ainda que alguns IDs de região sejam semelhantes aos códigos de país e estado geralmente usados. Para apps criados após fevereiro de 2020, o REGION_ID.r está incluído nos URLs do App Engine. Para apps existentes criados antes dessa data, o ID da região é opcional no URL.

Saiba mais sobre IDs de região.

O Pub/Sub mensagens assíncronas confiáveis de muitos para muitos entre os aplicativos. Os aplicativos do editor podem enviar mensagens para um tópico e outros aplicativos podem assinar esse tópico para receber as mensagens.

Neste documento, descrevemos como usar a biblioteca de cliente do Cloud para enviar e receber mensagens do Pub/Sub em um aplicativo do App Engine.

Pré-requisitos

Como clonar o app de amostra

Copie os aplicativos de amostra para sua máquina local e navegue até o diretório pubsub:

Go

v1.18 e posterior

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git
    cd golang-samples/appengine_flexible/pubsub

v1.15 e anteriores

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git
    cd golang-samples/appengine_flexible/go115_and_earlier/pubsub

Java

Versão 11/17

git clone https://github.com/GoogleCloudPlatform/java-docs-samples
cd java-docs-samples/flexible/java-11/pubsub/

Versão 8

git clone https://github.com/GoogleCloudPlatform/java-docs-samples
cd java-docs-samples/flexible/java-8/pubsub/

Node.js

git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples
cd nodejs-docs-samples/appengine/pubsub

PHP

git clone https://github.com/GoogleCloudPlatform/php-docs-samples.git
cd php-docs-samples/pubsub

Python

v3.8 e posterior

git clone https://github.com/GoogleCloudPlatform/python-docs-samples
cd python-docs-samples/appengine/flexible/pubsub

v3.7 e anteriores

git clone https://github.com/GoogleCloudPlatform/python-docs-samples
cd python-docs-samples/appengine/flexible_python37_and_earlier/pubsub

Ruby

versão 3.2

git clone https://github.com/GoogleCloudPlatform/ruby-docs-samples
cd ruby-docs-samples/appengine/flexible/pubsub/

versão 3.1 e anteriores

git clone https://github.com/GoogleCloudPlatform/ruby-docs-samples
cd ruby-docs-samples/appengine/flexible/ruby31-and-earlier/pubsub/

.NET

versão 6

git clone  https://github.com/GoogleCloudPlatform/dotnet-docs-samples
cd dotnet-docs-samples/appengine/flexible/Pubsub/Pubsub.Sample

versão 3.1 e anteriores

git clone https://github.com/GoogleCloudPlatform/dotnet-docs-samples
git checkout flex-dotnet3-and-earlier
cd dotnet-docs-samples/appengine/flexible/Pubsub

Crie um tópico e uma inscrição

Crie um tópico e uma assinatura. Isso inclui especificar o endpoint que receberá as solicitações do Pub/Sub:

Go

# Configure the topic
gcloud pubsub topics create YOUR_TOPIC_NAME

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

Substitua YOUR_TOKEN por um token aleatório secreto. Ele é usado pelo endpoint do push para verificar as solicitações.

Para usar o Pub/Sub com autenticação, crie outra assinatura:

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-auth-service-account=YOUR-SERVICE-ACCOUNT-EMAIL\
    --push-auth-token-audience=OPTIONAL_AUDIENCE_OVERRIDE\
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

# Your Google-managed service account
# `service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com` needs to have the
# `iam.serviceAccountTokenCreator` role.
PUBSUB_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\
    --role='roles/iam.serviceAccountTokenCreator'

Substitua YOUR-SERVICE-ACCOUNT-EMAIL pelo e-mail da conta de serviço.

Java

# Configure the topic
gcloud pubsub topics create YOUR_TOPIC_NAME

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

Substitua YOUR_TOKEN por um token aleatório secreto. Ele é usado pelo endpoint do push para verificar as solicitações.

Para usar o Pub/Sub com autenticação, crie outra assinatura:

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-auth-service-account=YOUR-SERVICE-ACCOUNT-EMAIL\
    --push-auth-token-audience=OPTIONAL_AUDIENCE_OVERRIDE\
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

# Your Google-managed service account
# `service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com` needs to have the
# `iam.serviceAccountTokenCreator` role.
PUBSUB_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\
    --role='roles/iam.serviceAccountTokenCreator'

Substitua YOUR-SERVICE-ACCOUNT-EMAIL pelo e-mail da conta de serviço.

Node.js

# Configure the topic
gcloud pubsub topics create YOUR_TOPIC_NAME

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

Substitua YOUR_TOKEN por um token aleatório secreto. Ele é usado pelo endpoint do push para verificar as solicitações.

Para usar o Pub/Sub com autenticação, crie outra assinatura:

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-auth-service-account=YOUR-SERVICE-ACCOUNT-EMAIL\
    --push-auth-token-audience=OPTIONAL_AUDIENCE_OVERRIDE\
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

# Your Google-managed service account
# `service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com` needs to have the
# `iam.serviceAccountTokenCreator` role.
PUBSUB_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\
    --role='roles/iam.serviceAccountTokenCreator'

Substitua YOUR-SERVICE-ACCOUNT-EMAIL pelo e-mail da conta de serviço.

PHP

# Configure the topic
gcloud pubsub topics create YOUR_TOPIC_NAME

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

Substitua YOUR_TOKEN por um token aleatório secreto. Ele é usado pelo endpoint do push para verificar as solicitações.

Para usar o Pub/Sub com autenticação, crie outra assinatura:

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-auth-service-account=YOUR-SERVICE-ACCOUNT-EMAIL\
    --push-auth-token-audience=OPTIONAL_AUDIENCE_OVERRIDE\
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

# Your Google-managed service account
# `service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com` needs to have the
# `iam.serviceAccountTokenCreator` role.
PUBSUB_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\
    --role='roles/iam.serviceAccountTokenCreator'

Substitua YOUR-SERVICE-ACCOUNT-EMAIL pelo e-mail da conta de serviço.

Python

# Configure the topic
gcloud pubsub topics create YOUR_TOPIC_NAME

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

Substitua YOUR_TOKEN por um token aleatório secreto. Ele é usado pelo endpoint do push para verificar as solicitações.

Para usar o Pub/Sub com autenticação, crie outra assinatura:

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-auth-service-account=YOUR-SERVICE-ACCOUNT-EMAIL\
    --push-auth-token-audience=OPTIONAL_AUDIENCE_OVERRIDE\
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

# Your Google-managed service account
# `service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com` needs to have the
# `iam.serviceAccountTokenCreator` role.
PUBSUB_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\
    --role='roles/iam.serviceAccountTokenCreator'

Substitua YOUR-SERVICE-ACCOUNT-EMAIL pelo e-mail da conta de serviço.

Ruby

# Configure the topic
gcloud pubsub topics create YOUR_TOPIC_NAME

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

Substitua YOUR_TOKEN por um token aleatório secreto. Ele é usado pelo endpoint do push para verificar as solicitações.

Para usar o Pub/Sub com autenticação, crie outra assinatura:

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-auth-service-account=YOUR-SERVICE-ACCOUNT-EMAIL\
    --push-auth-token-audience=OPTIONAL_AUDIENCE_OVERRIDE\
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

# Your Google-managed service account
# `service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com` needs to have the
# `iam.serviceAccountTokenCreator` role.
PUBSUB_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\
    --role='roles/iam.serviceAccountTokenCreator'

Substitua YOUR-SERVICE-ACCOUNT-EMAIL pelo e-mail da conta de serviço.

.NET

# Configure the topic
gcloud pubsub topics create YOUR_TOPIC_NAME

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

Substitua YOUR_TOKEN por um token aleatório secreto. Ele é usado pelo endpoint do push para verificar as solicitações.

Para usar o Pub/Sub com autenticação, crie outra assinatura:

# Configure the push subscription
gcloud pubsub subscriptions create YOUR_SUBSCRIPTION_NAME \
    --topic=YOUR_TOPIC_NAME \
    --push-auth-service-account=YOUR-SERVICE-ACCOUNT-EMAIL\
    --push-auth-token-audience=OPTIONAL_AUDIENCE_OVERRIDE\
    --push-endpoint=https://YOUR_PROJECT_ID.REGION_ID.r.appspot.com/push-handlers/receive_messages?token=YOUR_TOKEN \
    --ack-deadline=10

# Your Google-managed service account
# `service-{PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com` needs to have the
# `iam.serviceAccountTokenCreator` role.
PUBSUB_SERVICE_ACCOUNT="service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${PUBSUB_SERVICE_ACCOUNT}"\
    --role='roles/iam.serviceAccountTokenCreator'

Substitua YOUR-SERVICE-ACCOUNT-EMAIL pelo e-mail da conta de serviço.

Como definir variáveis de ambiente

Go

Edite o arquivo app.yaml para definir as variáveis de ambiente do tópico e do token de verificação:

env_variables:
  PUBSUB_TOPIC: your-topic
  # This token is used to verify that requests originate from your
  # application. It can be any sufficiently random string.
  PUBSUB_VERIFICATION_TOKEN: your-token

Java

Edite o arquivo app.yaml para definir as variáveis de ambiente do tópico e do token de verificação:

env_variables:
  PUBSUB_TOPIC: <your-topic-name>
  # This token is used to verify that requests originate from your
  # application. It can be any sufficiently random string.
  PUBSUB_VERIFICATION_TOKEN: <your-verification-token>

Node.js

Edite o arquivo app.yaml para definir as variáveis de ambiente do tópico e do token de verificação:

env_variables:
  PUBSUB_TOPIC: YOUR_TOPIC_NAME
  # This token is used to verify that requests originate from your
  # application. It can be any sufficiently random string.
  PUBSUB_VERIFICATION_TOKEN: YOUR_VERIFICATION_TOKEN

PHP

Edite seu arquivo index.php para configurar as variáveis de ambiente para seu tópico e sua assinatura:

$container->set('topic', 'php-example-topic');
$container->set('subscription', 'php-example-subscription');

Python

Edite o arquivo app.yaml para definir as variáveis de ambiente para o ID do projeto, tópico e token de verificação:

env_variables:
    PUBSUB_TOPIC: your-topic
    # This token is used to verify that requests originate from your
    # application. It can be any sufficiently random string.
    PUBSUB_VERIFICATION_TOKEN: 1234abc

Ruby

Edite o arquivo app.yaml para definir as variáveis de ambiente para o ID do projeto, tópico e token de verificação:

env_variables:
    PUBSUB_TOPIC: <pubsub-topic-name>
    # This token is used to verify that requests originate from your
    # application. It can be any sufficiently random string.
    PUBSUB_VERIFICATION_TOKEN: <verification-token>

.NET

versão 6

Edite o arquivo app.yaml para definir as variáveis de ambiente do tópico e do token de verificação:

runtime: aspnetcore
env: flex

runtime_config:
  operating_system: ubuntu22

env_variables:
  TEST_PROJECT_ID: your-project-id
  TEST_VERIFICATION_TOKEN: your-token
  TEST_TOPIC_ID: your-topic
  TEST_SUBSCRIPTION_ID: your-sub
  TEST_AUTH_SUBSCRIPTION_ID: your-auth-sub
  TEST_SERVICE_ACCOUNT_EMAIL: your-service-account-email

versão 3.1 e anteriores

Edite o arquivo appsettings.json para definir o ID do projeto:

{
  "Pubsub": {
    "ProjectId": "your-project-id",
    "VerificationToken": "your-secret-token",
    "TopicId": "your-topic",
    "SubscriptionId": "your-subscription",
    "AuthSubscriptionId": "your-auth-subscription",
    "ServiceAccountEmail": "your-service-account-email"
  },

  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

Revisão de código

O aplicativo de amostra usa a biblioteca de cliente do Pub/Sub.

Go

O aplicativo de amostra usa as variáveis de ambiente definidas no arquivo app.yaml (PUBSUB_TOPIC e PUBSUB_VERIFICATION_TOKEN) para a configuração.

As mensagens recebidas por essa instância são armazenadas em uma fatia:

messages   []string

A função pushHandler recebe mensagens enviadas, verifica o token e adiciona a mensagem à fração messages:


func pushHandler(w http.ResponseWriter, r *http.Request) {
	// Verify the token.
	if r.URL.Query().Get("token") != token {
		http.Error(w, "Bad token", http.StatusBadRequest)
		return
	}
	msg := &pushRequest{}
	if err := json.NewDecoder(r.Body).Decode(msg); err != nil {
		http.Error(w, fmt.Sprintf("Could not decode body: %v", err), http.StatusBadRequest)
		return
	}

	messagesMu.Lock()
	defer messagesMu.Unlock()
	// Limit to ten.
	messages = append(messages, string(msg.Message.Data))
	if len(messages) > maxMessages {
		messages = messages[len(messages)-maxMessages:]
	}
}

A função publishHandler publica novas mensagens no tópico.


func publishHandler(w http.ResponseWriter, r *http.Request) {
	ctx := context.Background()

	msg := &pubsub.Message{
		Data: []byte(r.FormValue("payload")),
	}

	if _, err := topic.Publish(ctx, msg).Get(ctx); err != nil {
		http.Error(w, fmt.Sprintf("Could not publish message: %v", err), 500)
		return
	}

	fmt.Fprint(w, "Message published.")
}

Java

O aplicativo de amostra usa os valores definidos no arquivo app.yaml para configurar variáveis de ambiente. Esses valores são usados pelo gerenciador da solicitação de push para confirmar que a solicitação veio do Pub/Sub e veio de uma fonte confiável:

String pubsubVerificationToken = System.getenv("PUBSUB_VERIFICATION_TOKEN");

O aplicativo de amostra mantém uma instância de banco de dados do Cloud Datastore para armazenar mensagens. O servlet PubSubPush recebe as mensagens enviadas por push e as adiciona à instância do banco de dados messageRepository:

versão 11/17

@WebServlet(value = "/pubsub/push")
@MultipartConfig()
public class PubSubPush extends HttpServlet {

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws IOException, ServletException {
    String pubsubVerificationToken = System.getenv("PUBSUB_VERIFICATION_TOKEN");
    // Do not process message if request token does not match pubsubVerificationToken
    if (pubsubVerificationToken == null
        || pubsubVerificationToken.compareTo(req.getParameter("token")) != 0) {
      resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
      return;
    }
    // parse message object from "message" field in the request body json
    // decode message data from base64
    Message message = getMessage(req);
    try {
      messageRepository.save(message);
      // 200, 201, 204, 102 status codes are interpreted as success by the Pub/Sub system
      resp.setStatus(HttpServletResponse.SC_OK);
    } catch (Exception e) {
      System.out.println(e);
      resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }
  }

versão 8

@WebServlet(value = "/pubsub/push")
public class PubSubPush extends HttpServlet {

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws IOException, ServletException {
    String pubsubVerificationToken = System.getenv("PUBSUB_VERIFICATION_TOKEN");
    // Do not process message if request token does not match pubsubVerificationToken
    if (req.getParameter("token").compareTo(pubsubVerificationToken) != 0) {
      resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
      return;
    }
    // parse message object from "message" field in the request body json
    // decode message data from base64
    Message message = getMessage(req);
    try {
      messageRepository.save(message);
      // 200, 201, 204, 102 status codes are interpreted as success by the Pub/Sub system
      resp.setStatus(HttpServletResponse.SC_OK);
    } catch (Exception e) {
      resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }
  }

O servlet PubSubPublish interage com o aplicativo da Web do App Engine para publicar novas mensagens e exibir mensagens recebidas:

@WebServlet(name = "Publish with PubSub", value = "/pubsub/publish")
public class PubSubPublish extends HttpServlet {

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws IOException, ServletException {
    Publisher publisher = this.publisher;
    try {
      String topicId = System.getenv("PUBSUB_TOPIC");
      // create a publisher on the topic
      if (publisher == null) {
        publisher = Publisher.newBuilder(
            ProjectTopicName.of(ServiceOptions.getDefaultProjectId(), topicId))
            .build();
      }
      // construct a pubsub message from the payload
      final String payload = req.getParameter("payload");
      PubsubMessage pubsubMessage =
          PubsubMessage.newBuilder().setData(ByteString.copyFromUtf8(payload)).build();

      publisher.publish(pubsubMessage);
      // redirect to home page
      resp.sendRedirect("/");
    } catch (Exception e) {
      resp.sendError(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage());
    }
  }

Node.js

O aplicativo de amostra usa os valores definidos no arquivo app.yaml para configurar variáveis de ambiente. Esses valores são usados pelo gerenciador da solicitação de push para confirmar que a solicitação veio do Pub/Sub e veio de uma fonte confiável:

// The following environment variables are set by the `app.yaml` file when
// running on App Engine, but will need to be manually set when running locally.
var PUBSUB_VERIFICATION_TOKEN = process.env.PUBSUB_VERIFICATION_TOKEN;
var pubsub = gcloud.pubsub({
    projectId: process.env.GOOGLE_CLOUD_PROJECT
});
var topic = pubsub.topic(process.env.PUBSUB_TOPIC);

O aplicativo de amostra mantém uma lista global para armazenar as mensagens recebidas por instância:

// List of all messages received by this instance
var messages = [];

Este método recebe mensagens enviadas e as adiciona à lista global messages:

app.post('/pubsub/push', jsonBodyParser, (req, res) => {
  if (req.query.token !== PUBSUB_VERIFICATION_TOKEN) {
    res.status(400).send();
    return;
  }

  // The message is a unicode string encoded in base64.
  const message = Buffer.from(req.body.message.data, 'base64').toString(
    'utf-8'
  );

  messages.push(message);

  res.status(200).send();
});

Para publicar novas mensagens e exibir as recebidas, é feita uma interação entre este método e o app da Web do App Engine:

app.get('/', (req, res) => {
  res.render('index', {messages, tokens, claims});
});

app.post('/', formBodyParser, async (req, res, next) => {
  if (!req.body.payload) {
    res.status(400).send('Missing payload');
    return;
  }

  const data = Buffer.from(req.body.payload);
  try {
    const messageId = await topic.publishMessage({data});
    res.status(200).send(`Message ${messageId} sent.`);
  } catch (error) {
    next(error);
  }
});

PHP

O aplicativo de amostra usa os valores definidos no arquivo app.yaml para configurar variáveis de ambiente. O gerenciador da solicitação de push usa esses valores para confirmar que a solicitação veio do Pub/Sub e foi originada de uma fonte confiável:

runtime: php
env: flex

O aplicativo de amostra mantém uma lista global para armazenar as mensagens recebidas por instância:

$messages = [];

O método pull recupera as mensagens do tópico que você criou e as adiciona à lista de mensagens:

// get PULL pubsub messages
$pubsub = new PubSubClient([
    'projectId' => $projectId,
]);
$subscription = $pubsub->subscription($subscriptionName);
$pullMessages = [];
foreach ($subscription->pull(['returnImmediately' => true]) as $pullMessage) {
    $pullMessages[] = $pullMessage;
    $messages[] = $pullMessage->data();
}
// acknowledge PULL messages
if ($pullMessages) {
    $subscription->acknowledgeBatch($pullMessages);
}

O método publish publica novas mensagens no tópico:

if ($message = (string) $request->getBody()) {
    // Publish the pubsub message to the topic
    $pubsub = new PubSubClient([
        'projectId' => $projectId,
    ]);
    $topic = $pubsub->topic($topicName);
    $topic->publish(['data' => $message]);
    return $response->withStatus(204);
}

Python

O aplicativo de amostra usa os valores definidos no arquivo app.yaml para configurar variáveis de ambiente. O gerenciador da solicitação de push usa esses valores para confirmar que a solicitação veio do Pub/Sub e foi originada de uma fonte confiável:

app.config['PUBSUB_VERIFICATION_TOKEN'] = \
    os.environ['PUBSUB_VERIFICATION_TOKEN']
app.config['PUBSUB_TOPIC'] = os.environ['PUBSUB_TOPIC']

O aplicativo de amostra mantém uma lista global para armazenar as mensagens recebidas por instância:

MESSAGES = []

Este método pubsub_push() recebe mensagens enviadas e as adiciona à lista global MESSAGES:

@app.route("/pubsub/push", methods=["POST"])
def pubsub_push():
    if request.args.get("token", "") != current_app.config["PUBSUB_VERIFICATION_TOKEN"]:
        return "Invalid request", 400

    envelope = json.loads(request.data.decode("utf-8"))
    payload = base64.b64decode(envelope["message"]["data"])

    MESSAGES.append(payload)

    # Returning any 2xx status indicates successful receipt of the message.
    return "OK", 200

O método index() interage com o aplicativo da Web do App Engine para publicar novas mensagens e exibir mensagens recebidas:

@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "GET":
        return render_template("index.html", messages=MESSAGES)

    data = request.form.get("payload", "Example payload").encode("utf-8")

    # publisher = pubsub_v1.PublisherClient()
    topic_path = publisher.topic_path(
        current_app.config["PROJECT"], current_app.config["PUBSUB_TOPIC"]
    )

    publisher.publish(topic_path, data=data)

    return "OK", 200

Ruby

O aplicativo de amostra usa os valores definidos no arquivo app.yaml para configurar variáveis de ambiente. O gerenciador da solicitação de push usa esses valores para confirmar que a solicitação veio do Pub/Sub e foi originada de uma fonte confiável:

topic = pubsub.topic ENV["PUBSUB_TOPIC"]
PUBSUB_VERIFICATION_TOKEN = ENV["PUBSUB_VERIFICATION_TOKEN"]

O aplicativo de amostra mantém uma lista global para armazenar as mensagens recebidas por instância:

# List of all messages received by this instance
messages = []

Este método recebe mensagens enviadas e as adiciona à lista global messages:

post "/pubsub/push" do
  halt 400 if params[:token] != PUBSUB_VERIFICATION_TOKEN

  message = JSON.parse request.body.read
  payload = Base64.decode64 message["message"]["data"]

  messages.push payload
end

Este método interage com o app da Web do App Engine para publicar novas mensagens e exibir as recebidas:

get "/" do
  @claims = claims
  @messages = messages

  slim :index
end

post "/publish" do
  topic.publish params[:payload]

  redirect "/", 303
end

.NET

versão 6

[HttpGet]
[HttpPost]
public async Task<IActionResult> IndexAsync(MessageForm messageForm)
{
    var model = new MessageList();
    if (!_options.HasGoodProjectId())
    {
        model.MissingProjectId = true;
        return View(model);
    }
    if (!string.IsNullOrEmpty(messageForm.Message))
    {
        // Publish the message.
        var pubsubMessage = new PubsubMessage()
        {
            Data = ByteString.CopyFromUtf8(messageForm.Message)
        };
        pubsubMessage.Attributes["token"] = _options.VerificationToken;
        await _publisher.PublishAsync(pubsubMessage);
        model.PublishedMessage = messageForm.Message;
    }
    // Render the current list of messages.
    model.Messages = s_receivedMessages.ToArray();
    model.AuthMessages = s_authenticatedMessages.ToArray();
    return View(model);
}

versão 3.1 e anteriores

[HttpGet]
[HttpPost]
public IActionResult Index(MessageForm messageForm)
{
    var model = new MessageList();
    if (!_options.HasGoodProjectId())
    {
        model.MissingProjectId = true;
        return View(model);
    }
    if (!string.IsNullOrEmpty(messageForm.Message))
    {
        // Publish the message.
        var pubsubMessage = new PubsubMessage()
        {
            Data = ByteString.CopyFromUtf8(messageForm.Message)
        };
        pubsubMessage.Attributes["token"] = _options.VerificationToken;
        _publisher.PublishAsync(pubsubMessage);
        model.PublishedMessage = messageForm.Message;
    }
    // Render the current list of messages.
    model.Messages = s_receivedMessages.ToArray();
    model.AuthMessages = s_authenticatedMessages.ToArray();
    return View(model);
}

Executar a amostra no local

Com a Google Cloud CLI em execução no local, você pode fornecer autenticação para usar as APIs do Google Cloud. Se tiver configurado o ambiente conforme descrito nos Pré-requisitos, você já terá executado o comando gcloud init, que fornece essa autenticação.

Go

Defina as variáveis de ambiente antes de iniciar o aplicativo:

export GOOGLE_CLOUD_PROJECT=[your-project-id]
export PUBSUB_VERIFICATION_TOKEN=[your-token]
export PUBSUB_TOPIC=[your-topic]
go run pubsub.go

Java

mvn clean package

Defina as variáveis de ambiente antes de iniciar o aplicativo:

export PUBSUB_VERIFICATION_TOKEN=[your-verification-token]
export PUBSUB_TOPIC=[your-topic]
mvn jetty:run

Node.js

Defina as variáveis de ambiente antes de iniciar o aplicativo:

export GOOGLE_CLOUD_PROJECT=[your-project-id]
export PUBSUB_VERIFICATION_TOKEN=[your-verification-token]
export PUBSUB_TOPIC=[your-topic]
npm install
npm start

PHP

Instale as dependências usando o Composer:

composer install

Defina as variáveis de ambiente antes de iniciar o aplicativo:

export GOOGLE_CLOUD_PROJECT=[your-project-id]
export PUBSUB_VERIFICATION_TOKEN=[your-verification-token]
export PUBSUB_TOPIC=[your-topic]
php -S localhost:8080

Python

Instale as dependências preferencialmente em um ambiente virtual.

Mac OS/Linux

  1. Crie um ambiente Python isolado:
    python3 -m venv env
    source env/bin/activate
  2. Se você não estiver no diretório que contém o código de amostra, navegue até o diretório que contém o código de amostra hello_world. Em seguida, instale as dependências:
    cd YOUR_SAMPLE_CODE_DIR
    pip install -r requirements.txt

Windows

Use o PowerShell para executar os pacotes Python.

  1. Localize a instalação do PowerShell.
  2. Clique com o botão direito do mouse no atalho do PowerShell e inicie-o como administrador.
  3. Crie um ambiente Python isolado.
    python -m venv env
    .\env\Scripts\activate
  4. Acesse o diretório do projeto e instale as dependências: Se você não estiver no diretório que contém o código de amostra, navegue até o diretório que contém o código de amostra hello_world. Em seguida, instale as dependências:
    cd YOUR_SAMPLE_CODE_DIR
    pip install -r requirements.txt

Defina as variáveis de ambiente antes de iniciar o aplicativo:

export GOOGLE_CLOUD_PROJECT=[your-project-id]
export PUBSUB_VERIFICATION_TOKEN=[your-verification-token]
export PUBSUB_TOPIC=[your-topic]
python main.py

Ruby

Instale as dependências:

bundle install

Defina as variáveis de ambiente antes de iniciar o aplicativo:

export GOOGLE_CLOUD_PROJECT=[your-project-id]
export PUBSUB_VERIFICATION_TOKEN=[your-verification-token]
export PUBSUB_TOPIC=[your-topic]
bundle exec ruby app.rb -p 8080

.NET

Execute os seguintes comandos no diretório raiz do aplicativo:

    dotnet restore
    dotnet run

No navegador da Web, digite http://localhost:5000/. Para sair do servidor da Web, pressione Ctrl+C na janela do terminal.

Como simular notificações push

Pelo aplicativo, é possível enviar mensagens localmente, mas não é possível receber mensagens push localmente. É possível simular uma mensagem de push com uma solicitação HTTP para o notification endpoint de push local. A amostra inclui o sample_message.json do arquivo.

Go

É possível usar curl ou um cliente httpie para enviar uma solicitação POST HTTP:

curl -H "Content-Type: application/json" -i --data @sample_message.json "localhost:8080/push-handlers/receive_messages?token=[your-token]"

Ou

http POST ":8080/push-handlers/receive_messages?token=[your-token]" < sample_message.json

Resposta:

HTTP/1.1 200 OK
Date: Tue, 13 Nov 2018 16:04:18 GMT
Content-Length: 0

Uma vez concluída a solicitação, será possível atualizar o localhost:8080 e conferir a mensagem na lista de mensagens recebidas.

Java

É possível usar curl ou um cliente httpie para enviar uma solicitação POST HTTP:

curl -H "Content-Type: application/json" -i --data @sample_message.json "localhost:8080/push-handlers/receive_messages?token=[your-token]"

Ou

http POST ":8080/push-handlers/receive_messages?token=[your-token]" < sample_message.json

Resposta:

HTTP/1.1 200 OK
Date: Wed, 26 Apr 2017 00:03:28 GMT
Content-Length: 0
Server: Jetty(9.3.8.v20160314)

Uma vez concluída a solicitação, será possível atualizar o localhost:8080 e ver a mensagem na lista de mensagens recebidas.

Node.js

É possível usar curl ou um cliente httpie para enviar uma solicitação POST HTTP:

curl -H "Content-Type: application/json" -i --data @sample_message.json "localhost:8080/push-handlers/receive_messages?token=[your-token]"

Ou

http POST ":8080/push-handlers/receive_messages?token=[your-token]" < sample_message.json

Resposta:

HTTP/1.1 200 OK
Connection: keep-alive
Date: Mon, 31 Aug 2015 22:19:50 GMT
Transfer-Encoding: chunked
X-Powered-By: Express

Uma vez concluída a solicitação, será possível atualizar o localhost:8080 e conferir a mensagem na lista de mensagens recebidas.

PHP

É possível usar curl ou um cliente httpie para enviar uma solicitação POST HTTP:

curl -i --data @sample_message.json "localhost:4567/push-handlers/receive_messages?token=[your-token]"

Ou

http POST ":4567/push-handlers/receive_messages?token=[your-token]" < sample_message.json

Uma vez concluída a solicitação, será possível atualizar o localhost:8080 e ver a mensagem na lista de mensagens recebidas.

Python

É possível usar curl ou um cliente httpie para enviar uma solicitação POST HTTP:

curl -H "Content-Type: application/json" -i --data @sample_message.json "localhost:8080/pubsub/push?token=[your-token]"

Ou

http POST ":8080/pubsub/push?token=[your-token]" < sample_message.json

Resposta:

HTTP/1.0 200 OK
Content-Length: 2
Content-Type: text/html; charset=utf-8
Date: Mon, 10 Aug 2015 17:52:03 GMT
Server: Werkzeug/0.10.4 Python/2.7.10

OK

Uma vez concluída a solicitação, será possível atualizar o localhost:8080 e conferir a mensagem na lista de mensagens recebidas.

Ruby

É possível usar curl ou um cliente httpie para enviar uma solicitação POST HTTP:

curl -i --data @sample_message.json "localhost:4567/push-handlers/receive_messages?token=[your-token]"

Ou

http POST ":4567/push-handlers/receive_messages?token=[your-token]" < sample_message.json

Resposta:

HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 13
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.3.1 (Ruby/2.3.0/2015-12-25)
Date: Wed, 20 Apr 2016 20:56:23 GMT
Connection: Keep-Alive

Hello, World!

Uma vez concluída a solicitação, será possível atualizar o localhost:8080 e ver a mensagem na lista de mensagens recebidas.

.NET

Para enviar uma solicitação HTTP POST:

Get-Content -Raw .\sample_message.json | Invoke-WebRequest -Uri
http://localhost:5000/Push?token=your-secret-token -Method POST -ContentType
'text/json' -OutFile out.txt

Uma vez concluída a solicitação, será possível atualizar o localhost:5000 e conferir a mensagem na lista de mensagens recebidas.

Como executar no App Engine

Para implantar o app de demonstração no App Engine usando a ferramenta de linha de comando gcloud:

Go

Execute o seguinte comando no diretório em que o arquivo app.yaml está localizado:

gcloud app deploy

Java

Para implantar o app usando o Maven, execute o seguinte:

mvn package appengine:deploy -Dapp.deploy.projectId=PROJECT_ID

Substitua PROJECT_ID pelo ID do projeto do Google Cloud. Se o arquivo pom.xmlespecificar o ID do projeto, não será necessário incluir a propriedade -Dapp.deploy.projectId no comando executado.

Node.js

Execute o seguinte comando no diretório em que o arquivo app.yaml está localizado:

gcloud app deploy

PHP

Execute o seguinte comando no diretório em que o arquivo app.yaml está localizado:

gcloud app deploy

Python

Execute o seguinte comando no diretório em que o arquivo app.yaml está localizado:

gcloud app deploy

Ruby

Execute o seguinte comando no diretório em que o arquivo app.yaml está localizado:

gcloud app deploy app.yaml

.NET

Execute o seguinte comando no diretório em que o arquivo app.yaml está localizado:

gcloud app deploy

Agora, é possível acessar o aplicativo em https://PROJECT_ID.REGION_ID.r.appspot.com. Use o formulário para enviar mensagens, mas não há garantias de qual instância do seu aplicativo receberá a notificação. É possível enviar várias mensagens e atualizar a página para ver a mensagem recebida.