[JAVA] Comment implémenter le verrouillage optimiste dans l'API REST

Aperçu

La modification de l'état d'une ressource est une opération implémentée sur n'importe quel système. À ce stade, compte tenu de la garantie d'intégrité, une sorte de mécanisme de verrouillage est nécessaire.

Ici, en référence à Zalando, nous assurerons la cohérence par un verrouillage optimiste lors de la mise à jour de l'API RESTful. Voyons quelle est l'idée dans ce cas. Après cela, nous examinerons ce qui se passerait si nous implémentions un verrouillage optimiste et les parties qui ne sont pas clairement énoncées dans Zalando.

Comment implémenter le verrouillage optimiste

Le Guide de Zalando sur l'API RESTful présente quatre façons d'obtenir un verrouillage optimiste.

Voyons comment ces quatre réalisent un verrouillage optimiste dans le cas de l'obtention d'informations de liste via l'API et de la mise à jour de l'une d'entre elles.

En-tête If-Match et en-tête ETag

Le flux de mise à jour et le flux de verrouillage optimiste sont illustrés dans la figure ci-dessous. Return with ʻEtag header Vérifiez la correspondance / non-concordance entre la valeur retournée côté client dans la partie et la valeur donnée à ʻIf-Match dans Update` avec l'en-tête ʻIf-Match, et voyez la correspondance / non-concordance du serveur API. Décide de mettre à jour.

If-Match-and-Etag.png

ETags dans l'entité de résultat

Le flux de mise à jour et le flux de verrouillage optimiste sont illustrés dans la figure ci-dessous. Utilisez Return List pour obtenir toutes les ressources associées au point de terminaison correspondant. À ce moment-là, définissez la valeur de chaque ressource sur seed, créez un etag avec un algorithme et incluez-le dans la réponse. Dans le serveur API, la mise à jour est possible selon que la valeur donnée à ʻIf-Match dans update avec l'en-tête ʻIf-Match est la même que la valeur etag recalculée de la ressource pour laquelle la mise à jour a été demandée. Juger.

結果エンティティにおけるETags.png

Numéro de version

Le flux de mise à jour et le flux de verrouillage optimiste sont illustrés dans la figure ci-dessous. client retourne une liste comprenant le numéro de version, et acquiert toutes les ressources associées au point final correspondant sous la forme comprenant le numéro de version. Le serveur API détermine si la mise à jour est possible ou non en fonction du fait que le numéro de version envoyé par ʻupdate` et le numéro de version de la ressource pour laquelle la mise à jour a été demandée sont identiques. S'il est mis à jour, le numéro de version de la ressource correspondante sera incrémenté.

バージョン番号.png

Last-Modified / If-Unmodified-Since Le flux de mise à jour et le flux de verrouillage optimiste sont illustrés dans la figure ci-dessous. Le client renvoie une liste avec l'en-tête Last-Modified pour obtenir toutes les ressources associées au point de terminaison correspondant. À ce moment-là, ajoutez la date et l'heure de la dernière modification de la ressource dans l'en-tête «Last-Modified». Le serveur API compare la date et l'heure envoyées avec ʻIf-Unmodified-Since (= la valeur de Last-Modified`) avec la date et l'heure de la dernière modification de la ressource pour laquelle la demande de mise à jour a été faite, et détermine si la mise à jour est possible ou non. .. (Si la date et l'heure de la dernière mise à jour de la ressource sont plus récentes, il est jugé que la mise à jour n'est pas possible)

Last-Modified_If-Unmodified-Since.png

Avantages / inconvénients de chaque méthode

Comment obtenir un verrouillage optimiste mérite Démérite
If-Faire correspondre l'en-tête et l'en-tête ETag ・ Solution RESTful ・ Le nombre de demandes augmente
ETags dans l'entité de résultat ・ Rock optimiste parfait -Les informations à ajouter à l'en-tête HTTP pénètrent dans l'objet métier
Numéro de version ・ Rock optimiste parfait -Les informations à ajouter à l'en-tête HTTP pénètrent dans l'objet métier
Last-Modified / If-Unmodified-Since ・ Parce qu'il est utilisé depuis longtemps, il a fait ses preuves.
・ N'interfère pas avec les objets métier
・ Facile à mettre en œuvre
・ Pas besoin de demandes supplémentaires autres que les demandes de mise à jour
-Si le côté API est composé de plusieurs instances, une synchronisation temporelle stricte est requise.

Un exemple concret de verrouillage optimiste par ETags` dans une entité résultat

La source suivante implémente l'acquisition et la mise à jour de liste avec le point de terminaison ʻoptimistic / etag`. https://github.com/nannany/optimistic-lock-demo La génération ETag se fait avec sha256 comme suit.


package nannany.optimistic.demo.util;

import com.google.common.hash.Hashing;

import static java.nio.charset.StandardCharsets.UTF_8;

public final class DemoUtils {

    @SuppressWarnings("UnstableApiUsage")
    public static String getHash(String origin) {
        return Hashing.sha256().hashString(origin, UTF_8).toString();
    }
}

Comme indiqué dans le gif ci-dessous, si les valeurs ETag correspondent, la mise à jour est réussie et si elles ne correspondent pas, 409 est renvoyé.

etag2019-09-23 17-43.gif

Exemple spécifique de verrouillage optimiste par Last-Modified / If-Unmodified-Since

La source suivante implémente l'acquisition et la mise à jour de liste avec le point de terminaison ʻoptimistic / lastModify`. https://github.com/nannany/optimistic-lock-demo La date et l'heure d'acquisition de la liste sont entrées dans la date et l'heure de la dernière mise à jour, et un verrouillage optimiste est effectué pour voir s'il y a des mises à jour de la ressource après cela.

Comme indiqué dans le gif ci-dessous, si la dernière date et heure modifiées de la ressource à mettre à jour est antérieure à la date et à l'heure reçues dans l'en-tête «Si-Non-Modifié-Depuis», la mise à jour est réussie, sinon 412 est retourné.

lastModify2019-09-23 17-55.gif

Considération

Considérons certaines des techniques de verrouillage optimistes qui ne sont pas spécifiées dans Zalando.

À propos de la différence entre ETagsetnuméro de version dans l'entité de résultat

À Zalando, les deux méthodes ci-dessus Avantages: Rock optimiste parfait Inconvénient: les informations à ajouter à l'en-tête HTTP pénètrent dans l'objet métier Il n'y a pas de différence claire entre les avantages et les inconvénients. (Je ne suis pas sûr du rock optimiste parfait car il n'y a pas d'explication détaillée)

Nous pensons que les différences entre les avantages et les inconvénients de ces deux méthodes sont les deux points suivants.

Le serveur API doit-il contenir un élément pour détecter les verrous optimistes?

Dans les deux méthodes, les informations de liste renvoyées au client contiennent des éléments (ETag et version) en dehors de l'objet métier. Cependant, du côté du serveur d'API, la valeur d'ETag peut générer une certaine valeur de l'objet métier en tant que valeur de départ, c'est-à-dire qu'il n'est pas nécessaire de conserver la valeur de ETag, tandis que la valeur de version est conservée du côté du serveur d'API. Doit être fait. D'autre part, si vous décidez de ne pas conserver la valeur ETag du côté du serveur API, vous devez calculer l'ETag à chaque fois que vous obtenez les informations de la liste, vous devez donc vous demander si cela est correct en termes de performances. C'est vrai.

En réfléchissant à la manière de simplifier les informations de persistance et à ce qu'il faut faire avec la performance, je pense que c'est un mérite et un inconvénient.

Difficulté à deviner la valeur pour juger s'il faut mettre à jour

Le numéro de version est fondamentalement une valeur qui est incrémentée de 1 à chaque mise à jour, et il est relativement facile de deviner le numéro de version qui peut être mis à jour. D'autre part, inférer la valeur de ETag nécessite l'algorithme utilisé pour générer ETag, quelle graine est utilisée lors de la génération d'ETag et la valeur de la graine au moment de la mise à jour, ce qui est plus difficile que de déduire le numéro de version. C'est considéré.

En ce qui concerne la sécurité, je pense que c'est un mérite et un inconvénient.

À propos de l'aspect sécurité de Last-Modified / If-Unmodified-Since

Dans Last-Modified / If-Unmodified-Since, si vous réécrivez la valeur de l'en-tête ʻIf-Unmodified-Since` du côté client et spécifiez l'avenir loin (comme le 31 décembre 9999), la ressource Même si la valeur a été mise à jour depuis «Last-Modified», il sera possible de mettre à jour par le haut.

Par conséquent, du point de vue de la sécurité, je ne pense pas que "Last-Modified / If-Unmodified-Since" soit fort.

Résumé

J'ai regardé la méthode de verrouillage optimiste répertoriée dans Zalando, mais à la fin j'ai pensé que je n'avais pas d'autre choix que de penser à une méthode qui devrait être prise en fonction des exigences du système que je construisais. Le fait que Zalando introduit également quatre méthodes signifie que la meilleure méthode d'implémentation de verrouillage optimiste n'a pas été conçue pour chaque système.

Cependant, au lieu de réfléchir à la manière d'implémenter le verrou optimiste de l'API RESTful à partir de 0, il est recommandé de l'implémenter en se référant à la description de Zalando etc. et en appliquant les avantages et inconvénients introduits à votre propre système. N'est-ce pas une solution réaliste?

référence

Zalando Journal des étudiants en sciences RFC7232

Recommended Posts

Comment implémenter le verrouillage optimiste dans l'API REST
Implémenter l'API REST avec Spring Boot
Comment implémenter le calcul de la date en Java
Comment implémenter le filtre de Kalman par Java
Comment appliquer les conventions de codage en Java
Comment implémenter la fonctionnalité de classement dans Rails
Comment implémenter le traitement asynchrone dans Outsystems
Comment implémenter un travail qui utilise l'API Java dans JobScheduler
Comment implémenter une fonctionnalité similaire dans Rails
Comment implémenter la pagination dans GraphQL (pour ruby)
Comment implémenter UICollectionView avec du code uniquement dans Swift
Comment implémenter la connexion invité en 5 minutes sur le portefeuille de rails
Comment implémenter une fonctionnalité intéressante dans Ajax avec Rails
Présentez swagger-ui à l'API REST implémentée dans Spring Boot
Résumé de la mise en œuvre des arguments par défaut en Java
Comment utiliser l'API Chain
Introduction à l'API EHRbase 2-REST
[Rails] Comment mettre en œuvre le scraping
[Java] Comment implémenter le multithreading
Comment appeler et utiliser l'API en Java (Spring Boot)
Comment implémenter l'affichage sur une seule ligne de TextView dans le développement Android
Découvrons comment recevoir avec Request Body avec l'API REST de Spring Boot
Comment utiliser Lombok au printemps
Comment trouver May'n dans XPath
Comment masquer la barre de défilement dans WebView
Comment itérer indéfiniment en Ruby
Essayez d'implémenter Yuma dans Ruby
Comment exécuter Ant dans Gradle
Comment maîtriser la programmation en 3 mois
Comment apprendre JAVA en 7 jours
Comment installer Bootstrap dans Ruby
Comment utiliser InjectorHolder dans OpenAM
Comment installer jQuery dans Rails 6
[Rails] Comment mettre en œuvre le classement par étoiles
Comment utiliser les classes en Java?
Comment nommer des variables en Java
Comment définir Lombok dans Eclipse
Essayez d'implémenter Yuma en Java
Comment concaténer des chaînes avec Java
Comment installer Swiper in Rails
[RubyOnRails] Comment implémenter le pull-down sur form_with en fonction des données de table
[swift5] Comment spécifier la couleur en hexadécimal
Comment créer votre propre API headless à l'aide de REST Builder de Liferay (partie 3)
Comment créer votre propre API headless à l'aide de REST Builder de Liferay (partie 2)
Prise en charge multilingue de Java Comment utiliser les paramètres régionaux
Comment changer le nom de l'application dans les rails
Implémenter l'autorisation API Gateway Lambda dans Java Lambda
Comment utiliser le volume nommé dans docker-compose.yml
Essayez d'implémenter l'ajout n-aire en Java
Comment filtrer JUnit Test dans Gradle
Comment insérer une vidéo dans Rails
Comment inclure Spring Tool dans Eclipse 4.6.3?
Comment ajouter un fichier jar dans ScalaIDE