Welcher HTTP-Statuscode soll zurückgegeben werden, wenn mehrere Aktionen mit unterschiedlichen Status enden?


72

Ich erstelle eine API, in der der Benutzer den Server auffordern kann, mehrere Aktionen in einer HTTP-Anforderung auszuführen. Das Ergebnis wird als JSON-Array mit einem Eintrag pro Aktion zurückgegeben.

Jede dieser Aktionen kann unabhängig voneinander fehlschlagen oder erfolgreich sein. Beispielsweise ist die erste Aktion möglicherweise erfolgreich, die Eingabe für die zweite Aktion ist möglicherweise schlecht formatiert und kann nicht überprüft werden, und die dritte Aktion verursacht möglicherweise einen unerwarteten Fehler.

Wenn es eine Anfrage pro Aktion gäbe, würde ich die Statuscodes 200, 422 bzw. 500 zurückgeben. Aber jetzt, wo es nur eine Anfrage gibt, welchen Statuscode soll ich zurückgeben?

Einige Optionen:

  • Geben Sie immer 200 zurück und geben Sie detailliertere Informationen im Körper an.
  • Befolgen Sie die obige Regel möglicherweise nur, wenn die Anforderung mehr als eine Aktion enthält?
  • Vielleicht 200 zurückgeben, wenn alle Anfragen erfolgreich sind, andernfalls 500 (oder ein anderer Code)?
  • Verwenden Sie einfach eine Anforderung pro Aktion und akzeptieren Sie den zusätzlichen Aufwand.
  • Etwas ganz anderes?

3
Ihre Frage ließ mich an eine andere denken: programmers.stackexchange.com/questions/309147/…
AilurusFulgens

7
Auch ein wenig verwandt: programmers.stackexchange.com/questions/305250/… (siehe die akzeptierte Antwort zur Trennung zwischen HTTP-Statuscodes und Anwendungscodes)

4
Was ist der Vorteil, den Sie durch die Gruppierung dieser Anforderungen erzielen? Geht es um Geschäftslogik, wie eine Transaktion über mehrere Ressourcen, oder geht es um Leistung? Oder etwas anderes?
Luc Franken

5
In diesem Fall würde ich dringend empfehlen, diese Leistung in anderen Bereichen zu verbessern. Probieren Sie optimistische Benutzeroberflächen aus, fordern Sie Stapelverarbeitung, Zwischenspeicherung usw. an, bevor Sie diese Komplexität in Ihre Geschäftsschicht implementieren. Wissen Sie genau, wo Sie am meisten Zeit verlieren?
Luc Franken

4
... seien Sie nicht zu hoffnungsvoll, dass die Leute diese Zustände richtig betrachten. Die meisten Programme suchen nur nach den häufigsten und schlagen fehl oder verhalten sich schlecht, wenn sie einen unerwarteten Statuscode erhalten. (Ich erinnere mich, dass es auf der DefCon auch eine Präsentation zum Schutz Ihrer Website vor Crawlern gab, in der zufällige Beendigungsstatus gesendet wurden, die der Browser ignoriert und einfach anzeigt, warum Crawler manchmal Fehler darstellen und so das Crawlen dieses Teils Ihrer Website stoppen.)
Bakuriu

Antworten:


21

Die kurze, direkte Antwort

Da die Anforderung von der Ausführung der Aufgabenliste spricht (Aufgaben sind die Ressource, von der wir hier sprechen), ist es sinnvoll, wenn die Aufgabengruppe zur Ausführung verschoben wurde (dh unabhängig vom Ausführungsergebnis) dass der Antwortstatus sein wird 200 OK. Wenn andernfalls ein Problem aufgetreten ist, das die Ausführung der Aufgabengruppe verhindert, z. B. ein Fehler bei der Validierung der Aufgabenobjekte , oder ein erforderlicher Dienst nicht verfügbar ist, sollte der Antwortstatus diesen Fehler anzeigen. Wenn die Ausführung der Tasks beginnt, da die auszuführenden Tasks im Anforderungshauptteil aufgeführt sind, würde ich davon ausgehen, dass die Ausführungsergebnisse im Antworthauptteil aufgeführt werden.


Die lange, philosophische Antwort

Dieses Dilemma tritt auf, weil Sie von dem abweichen, für das HTTP entwickelt wurde. Sie interagieren nicht mit ihm, um Ressourcen zu verwalten, sondern verwenden ihn als Mittel zum Aufrufen von Remotemethoden (was nicht sonderbar ist, jedoch ohne ein vorgefasstes Schema schlecht funktioniert).

Mit dem oben Gesagten und ohne den Mut, diese Antwort in einen langmeinenden Leitfaden zu verwandeln, ist das Folgende ein URI-Schema, das einem Ressourcenmanagement-Ansatz entspricht:

  • /tasks
    • GET listet alle Aufgaben auf, paginiert
    • POST Fügt eine einzelne Aufgabe hinzu
  • /tasks/task/[id]
    • GET antwortet mit dem Statusobjekt einer einzelnen Aufgabe
    • DELETE bricht eine Aufgabe ab oder löscht sie
  • /tasks/groups
    • GET listet alle Aufgabengruppen auf, paginiert
    • POST Fügt eine Gruppe von Aufgaben hinzu
  • /tasks/groups/group/[id]
    • GET antwortet mit dem Status einer Aufgabengruppe
    • DELETE Löscht / löscht die Aufgabengruppe

In dieser Struktur geht es um Ressourcen, nicht darum, was man mit ihnen machen soll. Was mit Ressourcen gemacht wird, ist das Anliegen eines anderen Dienstes.

Ein weiterer wichtiger Punkt ist, dass es ratsam ist, in einem HTTP-Request-Handler nicht zu lange zu blockieren. Ähnlich wie bei der Benutzeroberfläche sollte eine HTTP-Schnittstelle reagieren - in einem Zeitrahmen, der um einige Größenordnungen langsamer ist (da sich diese Schicht mit E / A befasst).

Der Schritt zum Entwerfen einer HTTP-Schnittstelle, mit der Ressourcen streng verwaltet werden, ist wahrscheinlich so schwierig wie das Entfernen der Arbeit von einem UI-Thread, wenn auf eine Schaltfläche geklickt wird. Es ist erforderlich, dass der HTTP-Server mit anderen Diensten kommuniziert, um Aufgaben auszuführen, anstatt sie im Anforderungshandler auszuführen. Dies ist keine flache Implementierung, sondern eine Richtungsänderung.


Einige Beispiele für die Verwendung eines solchen URI-Schemas

Ausführen einer einzelnen Aufgabe und Verfolgen des Fortschritts:

  • POST /tasks mit der auszuführenden Aufgabe
    • GET /tasks/task/[id]bis das Antwortobjekt completedeinen positiven Wert hat und gleichzeitig den aktuellen Status / Fortschritt anzeigt

Eine einzelne Aufgabe ausführen und auf ihren Abschluss warten:

  • POST /tasks mit der auszuführenden Aufgabe
    • GET /tasks/task/[id]?awaitCompletion=truetill completedhat einen positiven Wert (wahrscheinlich hat es ein Timeout, weshalb dies eine Schleife sein sollte)

Ausführen einer Aufgabengruppe und Verfolgen des Fortschritts:

  • POST /tasks/groups mit der Gruppe der auszuführenden Aufgaben
    • GET /tasks/groups/group/[groupId]bis die completedEigenschaft des Antwortobjekts einen Wert hat, der den Status der einzelnen Aufgabe anzeigt (3 von beispielsweise 5 Aufgaben erledigt)

Anfordern einer Ausführung für eine Aufgabengruppe und Warten auf deren Fertigstellung:

  • POST /tasks/groups mit der Gruppe der auszuführenden Aufgaben
    • GET /tasks/groups/group/[groupId]?awaitCompletion=true bis antwortet mit einem Ergebnis, das den Abschluss anzeigt (wahrscheinlich hat es eine Zeitüberschreitung, weshalb eine Schleife ausgeführt werden sollte)

Ich denke, darüber zu sprechen, was semantisch Sinn macht, ist der richtige Weg, dies zu erreichen. Vielen Dank!
Anders

2
Ich würde diese Antwort vorschlagen, wenn sie nicht schon da gewesen wäre. Es ist nicht möglich , mehrere Anfragen in einer einzigen HTTP-Anfrage zu stellen. Auf der anderen Seite ist es durchaus möglich, eine einzelne HTTP-Anfrage mit der Aufschrift "Führen Sie die folgenden Aktionen aus und teilen Sie mir die Ergebnisse mit" zu stellen. Und genau das passiert hier.
Martin Kochanski

Ich werde diese Antwort akzeptieren, auch wenn sie weit von den meisten Stimmen entfernt ist. Auch wenn andere Antworten gut sind, ist dies meiner Meinung nach der einzige Grund für die Semantik von HTTP.
Anders

87

Meine Stimme wäre, diese Aufgaben in getrennte Anträge aufzuteilen. Wenn jedoch zu viele Roundtrips ein Problem darstellen, bin ich auf den HTTP-Antwortcode 207 - Multi-Status gestoßen

Kopieren / Einfügen von diesem Link:

Eine Multi-Status-Antwort übermittelt Informationen zu mehreren Ressourcen in Situationen, in denen mehrere Statuscodes geeignet sein könnten. Der Standardtext einer Antwort mit mehreren Status ist eine HTTP-Entität text / xml oder application / xml mit einem Wurzelelement 'multistatus'. Weitere Elemente enthalten Statuscodes der Serien 200, 300, 400 und 500, die während des Methodenaufrufs generiert wurden. 100-Serien-Statuscodes DÜRFEN NICHT in einem XML-Antwortelement aufgezeichnet werden.

Obwohl '207' als allgemeiner Antwortstatuscode verwendet wird, muss der Empfänger den Inhalt des Multistatus-Antwortkörpers konsultieren, um weitere Informationen zum Erfolg oder Misserfolg der Methodenausführung zu erhalten. Die Antwort kann bei Erfolg, Teilerfolg und auch in Fehlersituationen verwendet werden.


22
207scheint das zu sein, was das OP will, aber ich möchte wirklich betonen, dass es wahrscheinlich eine schlechte Idee ist, diesen Multi-Request-in-One-Ansatz zu verfolgen. Wenn es um die Leistung geht, sollten Sie eine Architektur für horizontal skalierbare Systeme im Cloud-Stil entwickeln (was HTTP-basierte Systeme hervorragend können)
Reinstate Monica

44
@ DavidGrinberg Ich konnte nicht mehr widersprechen. Wenn die einzelnen Aktionen kostengünstig sind, kann der Aufwand für die Bearbeitung einer Anfrage erheblich höher sein als für die Aktion selbst. Ihr Vorschlag kann zu Szenarien führen, in denen mehrere Zeilen in einer Datenbank mit einer separaten Transaktion pro Zeile aktualisiert werden, da jede Zeile als separate Anforderung gesendet wird. Dies ist nicht nur schrecklich ineffizient, sondern bedeutet auch, dass es nicht möglich ist, mehrere Zeilen atomar zu aktualisieren, wenn dies erforderlich ist. Horizontale Skalierung ist wichtig, aber kein Ersatz für effiziente Entwürfe.
Kasperd

4
Gut gesagt und unter Hinweis auf ein typisches Problem von REST-API-Implementierungen, die von Personen ausgeführt werden, die sich nicht mit den tatsächlichen Geschäftsanforderungen wie Leistung und / oder Atomarität auskennen. Aus diesem Grund gibt es beispielsweise in der OData-REST-Spezifikation ein Stapelformat für mehrere Vorgänge in einem Aufruf - es besteht ein tatsächlicher Bedarf dafür.
TomTom

8
@TomTom, das OP will keine Atomarität. Das wäre viel einfacher zu entwerfen, da es nur einen Status einer atomaren Operation gibt. Die HTTP-Spezifikation ermöglicht auch Batch-Operationen für die Leistung über HTTP / 2-Multiplexing (natürlich ist die HTTP / 2-Unterstützung eine andere Angelegenheit, aber die Spezifikation erlaubt dies).
Paul Draper

2
@David Nachdem ich in der Vergangenheit an einigen HPC-Problemen gearbeitet habe, sind die Kosten für das Senden eines einzelnen Bytes meiner Erfahrung nach fast gleich hoch wie für das Senden von Tausenden (verschiedene Übertragungsmedien verursachen zwar einen unterschiedlichen Overhead, sind aber selten besser als dieser). Wenn also die Leistung ein Problem darstellt, kann ich nicht erkennen, dass das Senden mehrerer Anforderungen keinen hohen Aufwand bedeutet. Wenn Sie jetzt mehrere Anforderungen über dieselbe Verbindung multiplexen könnten, würde dieses Problem verschwinden, aber soweit ich weiß, ist dies nur eine Option mit HTTP / 2, und die Unterstützung dafür ist eher begrenzt. Oder vermisse ich etwas?
Voo

24

Obwohl Multi-Status eine Option ist, würde ich 200 (alles in Ordnung) zurückgeben, wenn alle Anforderungen erfolgreich waren, und andernfalls einen Fehler (500 oder vielleicht 207).

Der Standardfall sollte in der Regel 200 sein - alles funktioniert. Und Kunden sollten das nur überprüfen müssen. Und nur wenn der Fehlerfall aufgetreten ist, können Sie eine 500 (oder eine 207) zurückgeben. Ich denke, der 207 ist eine gültige Wahl im Fall von mindestens einem Fehler, aber wenn Sie das gesamte Paket als eine Transaktion sehen, können Sie auch 500 senden. - Der Client möchte die Fehlermeldung so oder so interpretieren.

Warum nicht immer 207 senden? - Weil Standardfälle einfach und Standard sein sollten. Während Ausnahmefälle außergewöhnlich sein können. Ein Kunde sollte den Antworttext nur lesen und weitere komplexe Entscheidungen treffen müssen, wenn eine Ausnahmesituation dies rechtfertigt.


6
Da stimme ich nicht ganz zu Wenn die Unteranfragen 1 und 3 erfolgreich waren, erhalten Sie eine kombinierte Ressource und müssen die kombinierte Antwort trotzdem überprüfen. Sie müssen nur noch einen Fall berücksichtigen. Wenn response = 200 oder subresponse 1 = 200, war request 1 erfolgreich. Wenn response = 200 oder subresponse 2 = 200, dann ist request 2 erfolgreich und so weiter, anstatt nur die sub response zu testen.
gnasher729

1
@ gnasher729 es kommt wirklich auf die anwendung an. Ich stelle mir eine benutzergesteuerte Aktion vor, die einfach mit (alles in Ordnung) zum nächsten Schritt übergeht, wenn alle Anfragen erfolgreich waren. - Wenn etwas schief gelaufen ist (globaler Status <= 200), müssen Sie detaillierte Fehler anzeigen und den Workflow ändern und müssen nur eine einzige Prüfung für jede Unteranforderung durchführen, da Sie sich in der Funktion "handleMixedState" und nicht in der Funktion "handleAllOk" befinden .
Falco

Es kommt wirklich darauf an, was es bedeutet. Zum Beispiel habe ich einen Endpunkt, der die Handelsstrategien steuert. Sie können eine Liste von Bezeichnern in einem Durchgang "starten". Rückgabe 200 bedeutet, dass die Operation (die Verarbeitung) erfolgreich war. Möglicherweise werden jedoch nicht alle erfolgreich gestartet. Was übrigens nicht einmal im unmittelbaren Ergebnis (das gestartet wird) zu sehen ist, da der Start einige Sekunden dauern kann. Die Semantik bei Aufrufen mit mehreren Operationen hängt vom Szenario ab.
TomTom

Ich würde höchstwahrscheinlich auch eine 500 senden, wenn es ein allgemeines Problem (z. B. Datenbankausfall) gibt, sodass der Server nicht einmal einzelne Anforderungen versucht, sondern nur einen allgemeinen Fehler zurückgeben kann. - Da es für den Benutzer 3 verschiedene Ergebnisse gibt: 1. Alles in Ordnung, 2. Allgemeines Problem, nichts funktioniert. 3. Einige Anforderungen sind fehlgeschlagen. -> Was normalerweise zu einem völlig anderen Programmablauf führt.
Falco

1
Ok, ein Ansatz wäre also: 207 = individueller Status für jede Anfrage. Sonst noch etwas: Der zurückgegebene Status gilt für jede Anfrage.
Sinnvoll

13

Eine Möglichkeit wäre, immer einen Statuscode 200 und dann bestimmte Fehler in Ihrem JSON-Dokumentkörper zurückzugeben. Genau so sind einige APIs konzipiert (sie geben immer einen Statuscode 200 zurück und lösen den Fehler im Hauptteil aus). Weitere Informationen zu den verschiedenen Ansätzen finden Sie unter http://archive.oreilly.com/pub/post/restful_error_handling.html


2
In diesem Fall gefällt mir die Idee, mit dem 200zu kennzeichnen, dass alles in Ordnung ist, die Anforderung eingegangen ist und gültig war , und dann mit dem JSON Details zu dem bereitzustellen, was in dieser Anforderung passiert ist (dh das Ergebnis der Transaktionen).
Rickcnagy

4

Ich denke neilsimp1 ist korrekt, aber ich würde eine Neugestaltung der gesendeten Daten empfehlen, so dass Sie später eine senden 206 - Acceptedund die Daten verarbeiten können. Vielleicht mit Rückrufen.

Das Problem beim Versuch, mehrere Aktionen in einer einzigen Anfrage zu senden, ist genau die Tatsache, dass jede Aktion einen eigenen "Status" haben sollte.

Betrachtet man den Import einer CSV (ich weiß nicht wirklich, worum es im OP geht, aber es ist eine einfache Version). POSTEN Sie die CSV und erhalten Sie eine 206 zurück. Später kann die CSV importiert werden und Sie können den Status des Imports mit einem GET (200) gegen eine URL abrufen, die pro Zeile Fehler anzeigt.

POST /imports/ -> 206
GET  /imports/1 -> 200
GET  /imports/1/errors -> 200 -> Has a list of errors

Das gleiche Muster kann auf viele Batch-Operationen angewendet werden

POST /operations/ -> 206
GET  /operations/1 -> 200
GET  /operations/1/errors -> 200 - > Has a list of errors.

Der Code, der den POST verarbeitet, muss nur überprüfen, ob das Format der Betriebsdaten gültig ist. Dann können die Operationen zu einem späteren Zeitpunkt ausgeführt werden. In einem Hintergrundarbeiter können Sie so beispielsweise einfacher skalieren. Dann können Sie den Status der Vorgänge jederzeit überprüfen. Sie können Polling oder Callbacks oder Streams oder was auch immer verwenden, um die Notwendigkeit zu erkennen, wann eine Reihe von Vorgängen abgeschlossen ist.


2

Hier gibt es schon viele gute Antworten, aber ein Aspekt fehlt:

Was ist der Vertrag, den Ihre Kunden erwarten?

HTTP-Returncodes sollten zumindest eine Erfolgs- / Misserfolgsunterscheidung anzeigen und somit die Rolle der "Ausnahmen armer Männer" spielen. Dann bedeutet 200 "Vertrag vollständig erfüllt" und 4xx oder 5xx bedeuten Nichterfüllung.

Naiv würde ich erwarten, dass der Vertrag Ihrer Mehrfachaktionsanforderung "alle meine Aufgaben erledigen" lautet, und wenn eine von ihnen fehlschlägt, war die Anforderung nicht (vollständig) erfolgreich. Normalerweise würde ich als Kunde 200 als "alles in Ordnung" verstehen, und Codes aus der 400er- und 500er-Familie zwingen mich, über die Folgen eines (teilweisen) Ausfalls nachzudenken. Verwenden Sie also 200 für "Alle Aufgaben erledigt" und 500 plus eine beschreibende Antwort für den Fall eines teilweisen Ausfalls.

Ein anderer hypothetischer Vertrag könnte sein, "alle Aktionen zu versuchen". Dann ist es völlig vertragsgemäß, wenn (einige) Aktionen fehlschlagen. Sie würden also immer 200 plus ein Ergebnisdokument zurückgeben, in dem Sie die Erfolgs- / Fehlerinformationen für die einzelnen Aufgaben finden.

Welchem ​​Vertrag möchten Sie also folgen? Beide sind gültig, aber der erste (200, nur wenn alles erledigt wurde) ist für mich intuitiver und entspricht besser den typischen Softwaremustern. Und für die (hoffentlich) meisten Fälle, in denen der Service alle Aufgaben erledigt hat, ist es für den Kunden unkompliziert, diesen Fall zu erkennen.

Ein letzter wichtiger Aspekt: ​​Wie teilen Sie Ihren Kunden Ihre Vertragsentscheidung mit? In Java würde ich beispielsweise Methodennamen wie "doAll ()" oder "tryToDoAll ()" verwenden. In HTTP können Sie die Endpunkt-URLs entsprechend benennen, in der Hoffnung, dass Ihre Client-Entwickler die Benennung sehen, lesen und verstehen (darauf würde ich nicht wetten). Ein Grund mehr, sich für den Vertrag mit der geringsten Überraschung zu entscheiden.


0

Antworten:

Verwenden Sie einfach eine Anforderung pro Aktion und akzeptieren Sie den zusätzlichen Aufwand.

Ein Statuscode beschreibt den Status eines Vorgangs. Daher ist es sinnvoll, eine Operation pro Anforderung durchzuführen.

Mehrere unabhängige Operationen unterbrechen das Prinzip, auf dem das Anforderungs-Antwort-Modell und die Statuscodes basieren. Du kämpfst gegen die Natur.

HTTP / 1.1 und HTTP / 2 haben den Aufwand für HTTP-Anforderungen erheblich verringert. Ich schätze, es gibt sehr wenige Situationen, in denen es ratsam ist, unabhängige Anfragen zu stapeln.


Das gesagt,

(1) Mit einer PATCH-Anforderung ( RFC 5789 ) können Sie mehrere Änderungen vornehmen . Dies setzt jedoch voraus, dass die Änderungen nicht eigenständig sind; Sie werden atomar angewendet (alles oder nichts).

(2) Andere haben auf den 207 Multi-Status-Code hingewiesen. Dies ist jedoch nur für WebDAV ( RFC 4918 ), eine Erweiterung von HTTP, definiert.

Der 207-Statuscode (Multi-Status) gibt den Status für mehrere unabhängige Vorgänge an (weitere Informationen finden Sie in Abschnitt 13).

...

Eine Multi-Status-Antwort übermittelt Informationen zu mehreren Ressourcen in Situationen, in denen mehrere Statuscodes geeignet sein könnten. Das Wurzelelement "multistatus" [XML] enthält null oder mehr Antwortelemente in beliebiger Reihenfolge, die jeweils Informationen zu einer einzelnen Ressource enthalten.

Eine 207-WebDAV-XML-Antwort wäre in einer Nicht-WebDAV-API so seltsam wie eine Ente. Mach das nicht.


1
Sie behaupten im Wesentlichen, dass @Anders eine hat XY-Problem hat . Möglicherweise haben Sie recht, aber leider bedeutet dies, dass Sie die von ihm gestellte Frage nicht beantwortet haben (welchen Statuscode Sie für eine Mehrfachaktionsanforderung verwenden sollten).
Azuaron

2
@Azuaron, welche Art von Gürtel eignet sich am besten, um Kinder zu schlagen? Ich denke, "N / A" ist eine zulässige Antwort. Außerdem hat Andres mehrere Anfragen in seine Ideenliste aufgenommen. Ich habe diese Option von ganzem Herzen unterstützt.
Paul Draper

Ich habe irgendwie übersehen, dass er das aufgelistet hat. In diesem Fall behaupte ich, dass es eine dumme Frage ist, Euer Ehren!
Azuaron,

1
@Azuaron Ich denke absolut, dass dies eine gültige Antwort ist. Wenn ich alles falsch mache, möchte ich, dass jemand es sagt und mir keine Anweisungen gibt, wie ich am besten von einer Klippe fahren kann.
Anders

1
Nichts verbietet es, JSON in der 207-Antwort zu senden, solange der Content-Type-Header richtig gesetzt ist und mit dem übereinstimmt, was der Client verlangt hat (Accept-Header).
Dolmen

0

Wenn Sie wirklich mehrere Aktionen in einer Anfrage haben müssen, warum nicht alle Aktionen in eine Transaktion im Backend einbinden? Auf diese Weise sind entweder alle erfolgreich oder alle scheitern.

Als Client, der die API verwendet, kann ich bei einem API-Aufruf den vollständigen Erfolg oder Misserfolg verkraften. Teilerfolge sind schwer zu bewältigen, da ich mit allen möglichen Folgezuständen umgehen müsste.


2
Ich nehme an, wenn die Anfrage atomar wäre, hätte er diese Frage nicht gestellt.
Andy

@Andy Vielleicht, aber Sie können nicht davon ausgehen, dass er alle Implikationen eines solchen Entwurfs berücksichtigt.
Dean

Die Anforderung sollte nicht atomar sein. Wenn z. B. # 2 fehlschlägt, sollten die von # 1 vorgenommenen Änderungen weiterhin bestehen bleiben. Daher ist es keine Option, alles in eine Transaktion zu packen.
Anders
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.