Envoyer des requêtes par lot

Ce document explique comment autoriser les appels d'API JSON par lot pour réduire le nombre de connexions HTTP que votre client doit effectuer lors de l'accès à Cloud Storage.

Présentation

Chaque connexion HTTP effectuée par votre client entraîne certains coûts. L'API JSON Cloud Storage accepte les requêtes par lot, ce qui permet à votre client d'intégrer plusieurs appels d'API dans une seule requête HTTP.

Voici quelques exemples de situations dans lesquelles l'utilisation de requêtes par lot peut s'avérer utile :

  • Mise à jour de métadonnées, telles que des autorisations, sur de nombreux objets
  • Suppression de nombreux objets

Dans chacun de ces cas, vous pouvez regrouper plusieurs appels en une seule requête HTTP plutôt que de les envoyer séparément. Toutes les requêtes internes doivent être transmises à la même API JSON Cloud Storage.

Vous ne devez pas inclure plus de 100 appels dans une même requête par lot. Si vous avez besoin d'effectuer plus d'appels, exécutez plusieurs requêtes par lot. La charge utile totale de la requête par lot doit être inférieure à 10 Mo.

Informations sur les lots

Une requête par lot est constituée de plusieurs appels d'API combinés en une seule requête HTTP, qui peut être envoyée au point de terminaison par lot Cloud Storage, à savoir https://storage.googleapis.com/batch/storage/v1. Cette section décrit la syntaxe des requêtes par lot plus en détail. Vous en trouverez un exemple plus bas.

Format d'une requête par lot

Une requête par lot est une requête HTTP standard unique qui comprend plusieurs appels d'API JSON Cloud Storage. Cette requête principale utilise le type de contenu multipart/mixed. La requête HTTP principale est composée de plusieurs parties contenant chacune une requête HTTP imbriquée.

Chaque partie commence par son en-tête HTTP Content-Type: application/http, La partie peut également comporter un en-tête Content-ID facultatif. Ces en-têtes marquent le début de la partie, mais ils sont distincts de la requête HTTP imbriquée. Cela signifie qu'une fois que le serveur a décomposé la requête par lot en requêtes distinctes, les en-têtes de parties sont ignorés.

Le corps de chaque partie est lui-même composé d'une requête HTTP complète dotée de son propre verbe, de son URL, de ses en-têtes et de son corps. Ces requêtes HTTP ne doivent contenir que le chemin de l'URL. Les URL complètes peuvent avoir un comportement indéfini.

Les en-têtes HTTP des requêtes par lot externes s'appliquent également à toutes les requêtes imbriquées, à l'exception des en-têtes Content- tels que Content-Type. Toutefois, si vous spécifiez un en-tête HTTP donné dans la requête externe et dans une requête imbriquée, la valeur de l'en-tête de la requête imbriquée remplace celle de la requête par lot externe pour cette requête spécifique.

Par exemple, si vous fournissez un en-tête Authorization pour une requête imbriquée spécifique, cet en-tête ne s'applique qu'à la requête qui l'a spécifié. Si vous fournissez un en-tête Authorization pour la requête externe, cet en-tête s'applique à toutes les requêtes imbriquées, sauf si elles le remplacent par leur propre en-tête Authorization.

Lorsque Cloud Storage reçoit la requête par lot, il applique les paramètres de requête et les en-têtes (selon le cas) de la requête externe à chaque partie, puis traite ces parties comme s'il s'agissait de requêtes HTTP distinctes.

Réponse à une requête par lot

La réponse Cloud Storage est une réponse HTTP standard unique avec un type de contenu multipart/mixed. Chaque partie de cette réponse principale est la réponse à l'une des requêtes de la requête par lot. L'ordre des réponses est le même que celui des requêtes.

Comme toutes les parties d'une requête, chaque partie de la réponse contient une réponse HTTP complète, qui comprend un code d'état, des en-têtes et un corps. Elles sont aussi précédées d'un en-tête Content-Type signalant le début de la partie. Pour en savoir plus sur les codes d'état, consultez la section Codes d'état et d'erreur HTTP pour l'API Cloud Storage JSON.

Si une partie donnée de la requête possède un en-tête Content-ID, la partie correspondante de la réponse dispose alors du même en-tête Content-ID. L'en-tête Content-ID de la réponse commence par response-, suivi de la valeur Content-ID utilisée dans la requête, comme indiqué dans l'exemple.

Exemple

L'exemple de traitement par lot suivant met à jour les métadonnées personnalisées pour trois objets de example-bucket.

Exemple de requête HTTP par lot

HTTP

POST /batch/storage/v1 HTTP/1.1
Host: storage.googleapis.com
Content-Length: 960
Content-Type: multipart/mixed; boundary="===============7330845974216740156=="
Authorization: Bearer ya29.AHES6ZRVmB7fkLtd1XTmq6mo0S1wqZZi3-Lh_s-6Uw7p8vtgSwg

--===============7330845974216740156==
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: <b29c5de2-0db4-490b-b421-6a51b598bd22+1>

PATCH /storage/v1/b/example-bucket/o/obj1 HTTP/1.1
Content-Type: application/json
accept: application/json
content-length: 31

{"metadata": {"type": "tabby"}}
--===============7330845974216740156==
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: <b29c5de2-0db4-490b-b421-6a51b598bd22+2>

PATCH /storage/v1/b/example-bucket/o/obj2 HTTP/1.1
Content-Type: application/json
accept: application/json
content-length: 32

{"metadata": {"type": "tuxedo"}}
--===============7330845974216740156==
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: <b29c5de2-0db4-490b-b421-6a51b598bd22+3>

PATCH /storage/v1/b/example-bucket/o/obj3 HTTP/1.1
Content-Type: application/json
accept: application/json
content-length: 32

{"metadata": {"type": "calico"}}
--===============7330845974216740156==--

Bibliothèques clientes

C++

La bibliothèque cliente C++ n'accepte pas les requêtes par lot.

C#

La bibliothèque cliente C# n'accepte pas les requêtes par lot.

Go

La bibliothèque cliente Go n'accepte pas les requêtes par lot.

Java

Pour en savoir plus, consultez la documentation de référence de l'API Cloud Storage en langage Java.

import com.google.api.gax.paging.Page;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageBatch;
import com.google.cloud.storage.StorageOptions;
import java.util.HashMap;
import java.util.Map;

public class BatchSetObjectMetadata {
  public static void batchSetObjectMetadata(
      String projectId, String bucketName, String directoryPrefix) {
    // The ID of your GCP project
    // String projectId = "your-project-id";

    // The ID of your GCS bucket
    // String bucketName = "your-unique-bucket-name";

    // The directory prefix. All objects in the bucket with this prefix will have their metadata
    // updated
    // String directoryPrefix = "yourDirectory/";

    Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
    Map<String, String> newMetadata = new HashMap<>();
    newMetadata.put("keyToAddOrUpdate", "value");
    Page<Blob> blobs =
        storage.list(
            bucketName,
            Storage.BlobListOption.prefix(directoryPrefix),
            Storage.BlobListOption.currentDirectory());
    StorageBatch batchRequest = storage.batch();

    // Add all blobs with the given prefix to the batch request
    for (Blob blob : blobs.iterateAll()) {
      batchRequest.update(blob.toBuilder().setMetadata(newMetadata).build());
    }

    // Execute the batch request
    batchRequest.submit();

    System.out.println(
        "All blobs in bucket "
            + bucketName
            + " with prefix '"
            + directoryPrefix
            + "' had their metadata updated.");
  }
}

Node.js

La bibliothèque cliente Node.js n'accepte pas les requêtes par lot.

PHP

La bibliothèque cliente PHP n'accepte pas les requêtes par lot.

Python

Pour en savoir plus, consultez la documentation de référence de l'API Cloud Storage en langage Python.


from google.cloud import storage


def batch_request(bucket_name, prefix=None):
    """
    Use a batch request to patch a list of objects with the given prefix in a bucket.

    Note that Cloud Storage does not support batch operations for uploading or downloading.
    Additionally, the current batch design does not support library methods whose return values
    depend on the response payload.
    See https://cloud.google.com/python/docs/reference/storage/latest/google.cloud.storage.batch
    """
    # The ID of your GCS bucket
    # bucket_name = "my-bucket"
    # The prefix of the object paths
    # prefix = "directory-prefix/"

    client = storage.Client()
    bucket = client.bucket(bucket_name)

    # Accumulate in a list the objects with a given prefix.
    blobs_to_patch = [blob for blob in bucket.list_blobs(prefix=prefix)]

    # Use a batch context manager to edit metadata in the list of blobs.
    # The batch request is sent out when the context manager closes.
    # No more than 100 calls should be included in a single batch request.
    with client.batch():
        for blob in blobs_to_patch:
            metadata = {"your-metadata-key": "your-metadata-value"}
            blob.metadata = metadata
            blob.patch()

    print(
        f"Batch request edited metadata for all objects with the given prefix in {bucket.name}."
    )

Ruby

Pour découvrir comment effectuer une requête par lot à l'aide de Ruby, consultez la documentation de référence de l'API Cloud Storage en langage Ruby.

Exemple de réponse HTTP par lot

Il s'agit de la réponse à l'exemple de requête HTTP abordé dans la section précédente.

HTTP/1.1 200 OK
Content-Type: multipart/mixed; boundary=batch_pK7JBAk73-E=_AA5eFwv4m2Q=
Date: Mon, 22 Jan 2018 18:56:00 GMT
Expires: Mon, 22 Jan 2018 18:56:00 GMT
Cache-Control: private, max-age=0
Content-Length: 3767

--batch_pK7JBAk73-E=_AA5eFwv4m2Q=
Content-Type: application/http
Content-ID: <response-b29c5de2-0db4-490b-b421-6a51b598bd22+1>

HTTP/1.1 200 OK
ETag: "lGaP-E0memYDumK16YuUDM_6Gf0/V43j6azD55CPRGb9b6uytDYl61Y"
Content-Type: application/json; charset=UTF-8
Date: Mon, 22 Jan 2018 18:56:00 GMT
Expires: Mon, 22 Jan 2018 18:56:00 GMT
Cache-Control: private, max-age=0
Content-Length: 846

{
 "kind": "storage#object",
 "id": "example-bucket/obj1/1495822576643790",
 .
 .
 .
 "metadata": {
  "type": "tabby"
  },
  .
  .
  .
}

--batch_pK7JBAk73-E=_AA5eFwv4m2Q=
Content-Type: application/http
Content-ID: <response-b29c5de2-0db4-490b-b421-6a51b598bd22+2>

HTTP/1.1 200 OK
ETag: "lGaP-E0memYDumK16YuUDM_6Gf0/91POdd-sxSAkJnS8Dm7wMxBSDKk"
Content-Type: application/json; charset=UTF-8
Date: Mon, 22 Jan 2018 18:56:00 GMT
Expires: Mon, 22 Jan 2018 18:56:00 GMT
Cache-Control: private, max-age=0
Content-Length: 846

{
 "kind": "storage#object",
 "id": "example-bucket/obj2/1495822576643790",
 .
 .
 .
 "metadata": {
  "type": "tuxedo"
  },
  .
  .
  .
}

--batch_pK7JBAk73-E=_AA5eFwv4m2Q=
Content-Type: application/http
Content-ID: <response-b29c5de2-0db4-490b-b421-6a51b598bd22+3>

HTTP/1.1 200 OK
ETag: "lGaP-E0memYDumK16YuUDM_6Gf0/d2Z1F1_ZVbB1dC0YKM9rX5VAgIQ"
Content-Type: application/json; charset=UTF-8
Date: Mon, 22 Jan 2018 18:56:00 GMT
Expires: Mon, 22 Jan 2018 18:56:00 GMT
Cache-Control: private, max-age=0
Content-Length: 846

{
 "kind": "storage#object",
 "id": "example-bucket/obj3/1495822576643790",
 .
 .
 .
 "metadata": {
  "type": "calico"
  },
  .
  .
  .
}

--batch_pK7JBAk73-E=_AA5eFwv4m2Q=--

Si la requête globale n'est pas correctement formatée et que Cloud Storage ne parvient pas à l'analyser en sous-requêtes, vous recevez une erreur 400. Sinon, Cloud Storage renvoie un code d'état 200, même si une partie ou l'ensemble des sous-requêtes échouent.

Lorsque la requête globale renvoie un code d'état 200, la réponse contient les résultats de chaque sous-requête, y compris un code d'état indiquant si la sous-requête a abouti ou échoué.