Escribe y responde mensajes de Pub/Sub

ID de región

REGION_ID es un código abreviado que Google asigna en función de la región que eliges cuando creas la app. El código no corresponde a un país ni a una provincia, aunque algunos ID de región puedan parecer similares a los códigos de país y provincia que se suelen usar. En el caso de las apps creadas después de febrero de 2020, REGION_ID.r se incluye en las URL de App Engine. En el caso de las apps existentes creadas antes de esta fecha, el ID de región es opcional en la URL.

Obtén más información acerca de los ID de región.

Pub/Sub proporciona mensajería asíncrona, confiable y de varios a varios entre aplicaciones. Las aplicaciones de publicador pueden enviar mensajes a un tema, y otras aplicaciones pueden suscribirse a ese tema para recibir los mensajes.

En este documento, se describe cómo usar la biblioteca cliente de Cloud para enviar y recibir mensajes de Pub/Sub en una aplicación de App Engine.

Requisitos previos

Cómo clonar la app de muestra

Copia las apps de muestra en tu máquina local y navega hasta el directorio pubsub:

Comienza a usarlo

v1.18 y posteriores

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

v1.15 y anteriores

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

Java

versión 11/17

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

versión 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 y posteriores

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

v3.7 y anteriores

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

Ruby

versión 3.2

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

versión 3.1 y anteriores:

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

.NET

Versión 6

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

versión 3.1 y anteriores:

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

Crea un tema y una suscripción

Crea un tema y una suscripción, lo que incluye especificar el extremo al que el servidor Pub/Sub debe enviar solicitudes:

Comienza a usarlo

# 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

Reemplaza YOUR_TOKEN con un token secreto aleatorio. El extremo lo utiliza para verificar las solicitudes.

Para usar Pub/Sub con autenticación, crea otra suscripción:

# 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 service agent
# `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'

Reemplaza YOUR-SERVICE-ACCOUNT-EMAIL por el correo electrónico de tu cuenta de servicio.

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

Reemplaza YOUR_TOKEN con un token secreto aleatorio. El extremo lo utiliza para verificar las solicitudes.

Para usar Pub/Sub con autenticación, crea otra suscripción:

# 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 service agent
# `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'

Reemplaza YOUR-SERVICE-ACCOUNT-EMAIL por el correo electrónico de tu cuenta de servicio.

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

Reemplaza YOUR_TOKEN con un token secreto aleatorio. El extremo lo utiliza para verificar las solicitudes.

Para usar Pub/Sub con autenticación, crea otra suscripción:

# 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 service agent
# `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'

Reemplaza YOUR-SERVICE-ACCOUNT-EMAIL por el correo electrónico de tu cuenta de servicio.

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

Reemplaza YOUR_TOKEN con un token secreto aleatorio. El extremo lo utiliza para verificar las solicitudes.

Para usar Pub/Sub con autenticación, crea otra suscripción:

# 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 service agent
# `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'

Reemplaza YOUR-SERVICE-ACCOUNT-EMAIL por el correo electrónico de tu cuenta de servicio.

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

Reemplaza YOUR_TOKEN con un token secreto aleatorio. El extremo lo utiliza para verificar las solicitudes.

Para usar Pub/Sub con autenticación, crea otra suscripción:

# 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 service agent
# `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'

Reemplaza YOUR-SERVICE-ACCOUNT-EMAIL por el correo electrónico de tu cuenta de servicio.

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

Reemplaza YOUR_TOKEN con un token secreto aleatorio. El extremo lo utiliza para verificar las solicitudes.

Para usar Pub/Sub con autenticación, crea otra suscripción:

# 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 service agent
# `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'

Reemplaza YOUR-SERVICE-ACCOUNT-EMAIL por el correo electrónico de tu cuenta de servicio.

.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

Reemplaza YOUR_TOKEN con un token secreto aleatorio. El extremo lo utiliza para verificar las solicitudes.

Para usar Pub/Sub con autenticación, crea otra suscripción:

# 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 service agent
# `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'

Reemplaza YOUR-SERVICE-ACCOUNT-EMAIL por el correo electrónico de tu cuenta de servicio.

Configure variables de entorno

Comienza a usarlo

Edita el archivo app.yaml a fin de establecer las variables de entorno para tu tema y token de verificación:

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

Edita el archivo app.yaml a fin de establecer las variables de entorno para tu tema y token de verificación:

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

Edita el archivo app.yaml a fin de establecer las variables de entorno para tu tema y token de verificación:

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

Edita tu archivo index.php a fin de establecer las variables de entorno para tu tema y suscripción:

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

Python

Edita el archivo app.yaml a fin de establecer las variables de entorno para el tema, el token de verificación y el ID del proyecto:

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

Edita el archivo app.yaml a fin de establecer las variables de entorno para el tema, el token de verificación y el ID del proyecto:

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

Versión 6

Edita el archivo app.yaml a fin de establecer las variables de entorno para el tema y el token de verificación:

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

versión 3.1 y anteriores:

Edita el archivo appsettings.json para configurar el ID del proyecto:

{
  "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"
    }
  }
}

Revisión de código

La app de muestra usa la biblioteca cliente de Pub/Sub.

Comienza a usarlo

La aplicación de muestra utiliza las variables de entorno que estableciste en el archivo app.yaml (PUBSUB_TOPIC y PUBSUB_VERIFICATION_TOKEN) para la configuración.

Los mensajes recibidos por esta instancia se almacenan en una porción:

messages   []string

La función pushHandler recibe mensajes enviados, verifica el token y agrega el mensaje a la porción 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:]
	}
}

La función publishHandler publica nuevos mensajes en el tema.


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

La app de muestra usa los valores que estableces en el archivo app.yaml para configurar las variables de entorno. El controlador de las solicitudes push utiliza estos valores para confirmar que la solicitud provenga de Pub/Sub y que se origine en una fuente confiable:

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

La app de muestra mantiene una instancia de base de datos de Cloud Datastore para almacenar mensajes. El servlet PubSubPush recibe los mensajes enviados y los agrega a la instancia de base de datos messageRepository:

versión 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);
    }
  }

versión 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);
    }
  }

El servlet PubSubPublish interactúa con la app web de App Engine para publicar mensajes nuevos y mostrar los recibidos:

@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

La app de muestra usa los valores que estableces en el archivo app.yaml para configurar las variables de entorno. El controlador de las solicitudes push utiliza estos valores para confirmar que la solicitud provenga de Pub/Sub y que se origine en una fuente confiable:

// 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);

La app de muestra mantiene una lista global a fin de almacenar los mensajes que recibe esta instancia:

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

Este método recibe mensajes enviados y los agrega a la 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();
});

Este método interactúa con la aplicación web de App Engine para publicar mensajes nuevos y mostrar los recibidos.

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

La app de muestra usa los valores que estableces en el archivo app.yaml para configurar las variables de entorno. El controlador de las solicitudes push usa estos valores para confirmar que la solicitud provenga de Pub/Sub y que se origine en una fuente confiable:

runtime: php
env: flex

La app de muestra mantiene una lista global a fin de almacenar los mensajes que recibe esta instancia:

$messages = [];

El método pull recupera los mensajes del tema que creaste y los agrega a la lista de mensajes:

// 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);
}

El método publish publica mensajes nuevos en el tema:

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

La app de muestra usa los valores que estableces en el archivo app.yaml para configurar las variables de entorno. El controlador de las solicitudes push usa estos valores para confirmar que la solicitud provenga de Pub/Sub y que se origine en una fuente confiable:

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

La app de muestra mantiene una lista global a fin de almacenar los mensajes que recibe esta instancia:

MESSAGES = []

El método pubsub_push() recibe mensajes enviados y los agrega a la 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

El método index() interactúa con la aplicación web de App Engine para publicar mensajes nuevos y mostrar los mensajes recibidos:

@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

La app de muestra usa los valores que estableces en el archivo app.yaml para configurar las variables de entorno. El controlador de las solicitudes push usa estos valores para confirmar que la solicitud provenga de Pub/Sub y que se origine en una fuente confiable:

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

La app de muestra mantiene una lista global a fin de almacenar los mensajes que recibe esta instancia:

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

Este método recibe mensajes enviados y los agrega a la 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 interactúa con la aplicación web de App Engine para publicar mensajes nuevos y mostrar los recibidos:

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

  slim :index
end

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

  redirect "/", 303
end

.NET

Versión 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);
}

versión 3.1 y 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);
}

Ejecuta la muestra de forma local

En la ejecución local, puedes usar la CLI de Cloud para proporcionar autenticación a fin de emplear las APIs de Google Cloud. Si configuraste tu entorno como se describe en Requisitos, ya ejecutaste el comando gcloud init que proporciona esta autenticación.

Comienza a usarlo

A continuación, configura las variables de entorno antes de iniciar la aplicación:

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

A continuación, configura las variables de entorno antes de iniciar la aplicación:

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

Node.js

A continuación, configura las variables de entorno antes de iniciar la aplicación:

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

PHP

Instala las dependencias con Composer:

composer install

A continuación, configura las variables de entorno antes de iniciar la aplicación:

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

Python

Instala dependencias; es preferible hacerlo en un entorno virtual.

macOS/Linux

  1. Crea un entorno aislado de Python:
    python3 -m venv env
    source env/bin/activate
  2. Si no estás en el directorio que contiene el código de muestra, navega al directorio que contiene el código de muestra hello_world. Luego, instala las dependencias:
    cd YOUR_SAMPLE_CODE_DIR
    pip install -r requirements.txt

Windows

Usa PowerShell para ejecutar tus paquetes de Python.

  1. Ubica la instalación de PowerShell.
  2. Haz clic derecho en el acceso directo a PowerShell y, luego, inícialo como administrador.
  3. Crea un entorno de Python aislado.
    python -m venv env
    .\env\Scripts\activate
  4. Navegue al directorio del proyecto y luego instale las dependencias. Si no estás en el directorio que contiene el código de muestra, navega al directorio que contiene el código de muestra hello_world. Luego, instala las dependencias:
    cd YOUR_SAMPLE_CODE_DIR
    pip install -r requirements.txt

A continuación, configura las variables de entorno antes de iniciar la aplicación:

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

Ruby

Instala las dependencias:

bundle install

A continuación, configura las variables de entorno antes de iniciar la aplicación:

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

Ejecuta los siguientes comandos desde el directorio raíz de tu aplicación:

    dotnet restore
    dotnet run

En tu navegador web, ingresa http://localhost:5000/. Para salir del servidor web, presiona Ctrl+C en la ventana de terminal.

Simula notificaciones push

La aplicación puede enviar mensajes de forma local, pero no puede recibir mensajes push localmente. Sin embargo, puedes simular un mensaje push; para ello, envía una solicitud HTTP al extremo de notificación push local. La muestra incluye el archivo sample_message.json.

Comienza a usarlo

Puedes usar curl o un cliente httpie para enviar una solicitud HTTP POST:

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

O

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

Respuesta:

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

Una vez completada la solicitud, puedes actualizar localhost:8080 y ver el mensaje en la lista de mensajes recibidos.

Java

Puedes usar curl o un cliente httpie para enviar una solicitud HTTP POST:

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

O

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

Respuesta:

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

Una vez completada la solicitud, puedes actualizar localhost:8080 y ver el mensaje en la lista de mensajes recibidos.

Node.js

Puedes usar curl o un cliente httpie para enviar una solicitud HTTP POST:

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

O

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

Respuesta:

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

Una vez completada la solicitud, puedes actualizar localhost:8080 y ver el mensaje en la lista de mensajes recibidos.

PHP

Puedes usar curl o un cliente httpie para enviar una solicitud HTTP POST:

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

O

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

Una vez completada la solicitud, puedes actualizar localhost:8080 y ver el mensaje en la lista de mensajes recibidos.

Python

Puedes usar curl o un cliente httpie para enviar una solicitud HTTP POST:

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

O

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

Respuesta:

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

Una vez completada la solicitud, puedes actualizar localhost:8080 y ver el mensaje en la lista de mensajes recibidos.

Ruby

Puedes usar curl o un cliente httpie para enviar una solicitud HTTP POST:

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

O

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

Respuesta:

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!

Una vez completada la solicitud, puedes actualizar localhost:8080 y ver el mensaje en la lista de mensajes recibidos.

.NET

Para enviar una solicitud 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

Una vez completada la solicitud, puedes actualizar localhost:5000 y ver el mensaje en la lista de mensajes recibidos.

Ejecuta en App Engine

Para implementar la app de demostración en App Engine mediante la herramienta de línea de comandos de gcloud, haz lo siguiente:

Go

Ejecuta el siguiente comando desde el directorio en el que se encuentra el archivo app.yaml:

gcloud app deploy

Java

Para implementar tu aplicación con Maven, ejecuta los siguientes comandos:

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

Reemplaza PROJECT_ID por el ID del proyecto de Google Cloud. Si tu archivo pom.xml ya especifica tu ID del proyecto, no necesitas incluir la propiedad -Dapp.deploy.projectId en el comando que ejecutas.

Node.js

Ejecuta el siguiente comando desde el directorio en el que se encuentra el archivo app.yaml:

gcloud app deploy

PHP

Ejecuta el siguiente comando desde el directorio en el que se encuentra el archivo app.yaml:

gcloud app deploy

Python

Ejecuta el siguiente comando desde el directorio en el que se encuentra el archivo app.yaml:

gcloud app deploy

Ruby

Ejecuta el siguiente comando desde el directorio en el que se encuentra el archivo app.yaml:

gcloud app deploy app.yaml

.NET

Ejecuta el siguiente comando desde el directorio en el que se encuentra el archivo app.yaml:

gcloud app deploy

Ahora puedes acceder a la aplicación en https://PROJECT_ID.REGION_ID.r.appspot.com. Puedes usar el formulario para enviar mensajes, pero no hay forma de garantizar qué instancia de tu aplicación recibirá la notificación. Puedes enviar varios mensajes y actualizar la página para ver el mensaje recibido.