Scrittura di messaggi Cloud Pub/Sub e risposta a tali messaggi

ID regione

REGION_ID è un codice abbreviato assegnato da Google in base alla regione selezionata al momento della creazione dell'app. Non corrisponde a un paese o a una provincia, anche se alcuni ID regione possono apparire simili ai codici di paese e provincia di uso comune. Per le app create dopo febbraio 2020, REGION_ID.r è incluso negli URL di App Engine. Per le app esistenti create prima di questa data, l'ID regione è facoltativo nell'URL.

Scopri di più sugli ID regione.

Pub/Sub fornisce messaggi asincroni affidabili, many-to-many, tra le applicazioni. Le applicazioni del publisher possono inviare messaggi a un argomento, mentre le altre applicazioni possono sottoscrivere quell'argomento per ricevere i messaggi.

Questo documento descrive come utilizzare la libreria client Cloud per inviare e ricevere messaggi Pub/Sub in un'app Java 8.

Prerequisiti

  • Segui le istruzioni nella sezione "Hello, World!" per Java 8 su App Engine per configurare l'ambiente e il progetto e per capire come sono strutturate le app Java 8 di App Engine.
  • Prendi nota e salva l'ID progetto, perché ti servirà per eseguire l'applicazione di esempio descritta in questo documento.

Clonazione dell'app di esempio

Copia le app di esempio nella tua macchina locale e vai alla directory pubsub:

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

Creazione di un argomento e di una sottoscrizione

Crea un argomento e una sottoscrizione, che includa la specifica dell'endpoint a cui il server Pub/Sub deve inviare le richieste:

 bv
# 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

Sostituisci YOUR_TOKEN con un token casuale del secret. L'endpoint push utilizza questo metodo per verificare le richieste.

Per utilizzare Pub/Sub con l'autenticazione, crea un'altra sottoscrizione:

# 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'
Sostituisci "YOUR-SERVICE-ACCOUNT-EMAIL" con l'indirizzo email del tuo [account di servizio](/appengine/docs/pdfs/configure-service-accounts). ### Impostazione delle variabili di ambiente {: edit_appyaml} Modifica il file " appengine-web.xml " per impostare le variabili di ambiente per l'argomento e il token di verifica:
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <threadsafe>true</threadsafe>
  <runtime>java8</runtime>

  <env-variables>
    <env-var name="PUBSUB_TOPIC" value="your-topic" />
    <env-var name="PUBSUB_VERIFICATION_TOKEN" value="your-verification-token" />
  </env-variables>
</appengine-web-app>
## Revisione del codice L'app di esempio utilizza la [libreria client Cloud](https://googleapis.dev/java/google-cloud-clients/latest/index.html){: class="external"}. L'app di esempio utilizza i valori impostati nel file "appengine-web.xml" per configurare le variabili di ambiente. Il gestore delle richieste push utilizza questi valori per confermare che la richiesta provenga da Pub/Sub e che abbia avuto origine da una fonte attendibile: String pubsubVerificationToken = System.getenv("PUBSUB_VERIFICATION_TOKEN"); L'app di esempio gestisce un'istanza di database Cloud Datastore per archiviare i messaggi. Il servlet "PubSubPush" riceve i messaggi inviati tramite push e li aggiunge all'istanza di database "messageRepository":
@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(102);
    } catch (Exception e) {
      resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    }
  }

  private Message getMessage(HttpServletRequest request) throws IOException {
    String requestBody = request.getReader().lines().collect(Collectors.joining("\n"));
    JsonElement jsonRoot = JsonParser.parseString(requestBody).getAsJsonObject();
    String messageStr = jsonRoot.getAsJsonObject().get("message").toString();
    Message message = gson.fromJson(messageStr, Message.class);
    // decode from base64
    String decoded = decode(message.getData());
    message.setData(decoded);
    return message;
  }

  private String decode(String data) {
    return new String(Base64.getDecoder().decode(data));
  }

  private final Gson gson = new Gson();
  private MessageRepository messageRepository;

  PubSubPush(MessageRepository messageRepository) {
    this.messageRepository = messageRepository;
  }

  public PubSubPush() {
    this.messageRepository = MessageRepositoryImpl.getInstance();
  }
}
Il servlet "PubSubPubblica" interagisce con l'app web App Engine per pubblicare nuovi messaggi e visualizzare i messaggi ricevuti:
/*
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.appengine.pubsub;

import com.google.cloud.ServiceOptions;
import com.google.cloud.pubsub.v1.Publisher;
import com.google.protobuf.ByteString;
import com.google.pubsub.v1.ProjectTopicName;
import com.google.pubsub.v1.PubsubMessage;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.HttpStatus;

@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) {
        ProjectTopicName topicName =
            ProjectTopicName.newBuilder()
                .setProject(ServiceOptions.getDefaultProjectId())
                .setTopic(topicId)
                .build();
        publisher = Publisher.newBuilder(topicName).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());
    }
  }

  private Publisher publisher;

  public PubSubPublish() {}

  PubSubPublish(Publisher publisher) {
    this.publisher = publisher;
  }
}
## Esecuzione dell'esempio in locale {: #run_the_sample_locally} Quando viene eseguita in locale, puoi utilizzare Google Cloud CLI per fornire l'autenticazione per l'utilizzo delle API Google Cloud. Supponendo che tu abbia configurato l'ambiente come descritto nella sezione [Prerequisiti](#prerequisites), hai già eseguito il comando "gcloud init", che fornisce questa autenticazione. mvn clean Package Quindi, imposta le variabili di ambiente prima di avviare l'applicazione: Export PUBSUB_Verifica_TOKEN=[your-verification-token] esportazione PUBSUB_TOPIC=[your-topic] mvn appengine:run ### Simulazione di notifiche push {: simulate_push_notifications} L'applicazione può inviare messaggi in locale, ma non è in grado di ricevere le notifiche push in locale. Tuttavia, puoi simulare un messaggio push inviando una richiesta HTTP all'endpoint di notifica push locale. L'esempio include il file "sample_message.json" e il client "sample_message.json" per inviare una richiesta HTTP 'POST1': curl -H "Content-Type: application/token0" -i --data @sample_message8.8 per inviare una richiesta HTTP 'POST1': curl -H "Content-Type: application/token0" -i --data @sample_message8.8 ## Esecuzione su App Engine {: #run_on_app_engine} Per eseguire il deployment dell'app demo in App Engine utilizzando lo strumento a riga di comando "gcloud", esegui questo comando dalla directory in cui si trova il file "pom.xml":
mvn package appengine:deploy -Dapp.deploy.projectId=PROJECT_ID

Sostituisci PROJECT_ID con l'ID del tuo progetto Google Cloud. Se il file pom.xml specifica già il tuo ID progetto, non è necessario includere la proprietà -Dapp.deploy.projectId nel comando che esegui.

Ora puoi accedere all'applicazione all'indirizzo https://PROJECT_ID.REGION_ID.r.appspot.com. Puoi utilizzare il modulo per inviare messaggi, ma non vi è alcuna garanzia di quale istanza della tua richiesta riceverà la notifica. Puoi inviare più messaggi e aggiornare la pagina per vedere il messaggio ricevuto.