Doppelte Vorgänge durch Idempotenz vermeiden
Offene Handlungen wiederfinden und eine zusätzliche Absicht erst durch eine ausdrückliche neue Aktion beginnen.

Derselbe Wunsch ist nicht automatisch ein neuer Vorgang
Eine Person drückt zweimal auf Absenden oder sieht nach einer unterbrochenen Antwort keinen eindeutigen Erfolg. Die Anwendung erhält dadurch möglicherweise mehrere Anfragen für dieselbe beabsichtigte Handlung. Idempotenz bedeutet hier, diese Wiederholung derselben Handlung ohne eine zweite fachliche Wirkung zu behandeln. Dafür muss der Server den Vorgang wiedererkennen können. Die bloße Anzahl der HTTP-Anfragen beschreibt noch nicht die Zahl tatsächlich gewünschter Vormerkungen.
Unser eigener fiktiver Fall ist ein Workshop mit zunächst drei Plätzen. Eine Vormerkung umfasst einen oder zwei Plätze. Der vollständige PHP-Kern speichert die Vormerkung gemeinsam mit einem eindeutigen Vorgangsbeleg. Eine JavaScript-Oberfläche behält Vorgangskennung und Auswahl bei einer unklaren Antwort. Sie erzeugt erst dann eine neue Absicht, wenn die Person dies nach einem eindeutigen Ergebnis ausdrücklich auslöst.
Der Versuch nimmt keine reale Buchung entgegen und verarbeitet keine Kundendaten. Seine 83 ausgeführten Bedingungen verbinden tatsächliche PHP-Prozesse mit echten Browserabläufen. Besonders wichtig ist der Unterschied zum automatischen Ereignisempfang eines Webhooks: Hier geht es um die Absicht einer Person, die sichtbare Korrektur und einen bewusst begonnenen neuen Vorgang. Diese Bedeutung wird nicht durch eine zufällige technische Wiederholung festgelegt.
Die Handlung vor ihrer Übermittlung identifizieren
Der Browser erzeugt beim ersten tatsächlichen Absenden eine zufällige UUID für den Vorgang. Diese Kennung bleibt für seine weiteren Versuche gleich. Gleichzeitig wird die gewählte Anzahl als eigener einfacher Datenstand übernommen. Eine spätere Wiederholung soll nicht zufällig andere inzwischen im Formular sichtbare Werte mit derselben Kennung senden. Im Beispiel bleiben die Auswahlfelder deshalb während des offenen Vorgangs gesperrt.
Die Kennung selbst ist kein Passwort und keine Berechtigung. Sie erlaubt nur die Zuordnung innerhalb eines bereits festgelegten Anwendungskontexts. Eine neue Kennung bei jedem erneuten Netzwerkversuch würde den Zweck gerade verfehlen. Der Server könnte dann nicht unterscheiden, ob dieselbe Absicht wiederholt oder eine weitere Vormerkung ausdrücklich gewünscht wurde. Der Lebenszyklus des Schlüssels gehört daher zur fachlichen Bedienung.
Die Funktion crypto.randomUUID benötigt ihren passenden Browserkontext. Unser ausgeführter Entwurf läuft auf einer lokalen vertrauenswürdigen Entwicklungsadresse. Für eine echte Webseite werden unterstützte Browser und der sichere Kontext geprüft. Der Beitrag ersetzt diese Einbindung nicht durch eine schwache selbst gebaute Zufallszahl. Zugleich darf aus einer gut erzeugten UUID keine allgemeine Aussage über Authentifizierung oder Zugriffsschutz abgeleitet werden.
Browserkomfort und Serverentscheidung gemeinsam verwenden
Während der laufenden Anfrage sperrt die Oberfläche die auslösende Schaltfläche. Ein Doppelklick erzeugt im kontrollierten Browserversuch deshalb nur eine Übermittlung. Dieser Komfort ist hilfreich, löst die Aufgabe aber nicht allein. Ein anderer Client, mehrere Fenster oder ein späterer Wiederholungsversuch können weiterhin weitere Anfragen erzeugen. Die maßgebliche Entscheidung liegt deshalb zusätzlich im gemeinsamen Datenbankzustand des Servers.
Für die Doppelklickprüfung wird die Anfrage im Browser gezielt kurz zurückgehalten. Das ist eine kontrollierte Bedingung und keine gemessene reale Netzwerklatenz. Der Server erhält danach die tatsächliche Anfrage. Unabhängig davon starten weitere Prüfungen zwei PHP-Prozesse gleichzeitig. Beide verwenden dieselbe Vorgangskennung. Sie erhalten denselben Beleg und erzeugen zusammen nur eine Vormerkung.
Diese Verbindung ist praktischer als ein einzelner Mechanismus mit einer zu großen Behauptung. Eine gesperrte Schaltfläche verringert unnötige Übertragungen. Eine stabile Kennung macht Wiederholungen zuordenbar. Die Transaktion begrenzt ihre fachliche Wirkung. Erst die gemeinsam ausgeführten Fälle zeigen, ob diese Ebenen im konkreten Ablauf zusammenpassen. Kein einzelnes CSS-Attribut kann diese Serverentscheidung stellvertretend treffen.
Den Schlüssel im richtigen Benutzerbereich führen
Der Datenbankschlüssel besteht aus dem vertrauenswürdigen Akteur und der Vorgangskennung. Dadurch können zwei unterschiedliche berechtigte Kontexte dieselbe zufällig gewählte Kennung besitzen, ohne den Beleg des anderen zu erhalten. Der Test verwendet dafür zwei ausdrücklich fiktive Akteure. Beide erhalten ihre eigene Vormerkung, solange die gemeinsame Kapazität dafür reicht. Die Kapazitätsregel bleibt unabhängig von dieser Trennung bestehen.
Der Akteur wird dem PHP-Kern von der Anwendung übergeben. Er stammt nicht aus einem frei wählbaren JSON-Feld. Die isolierte HTTP-Versuchsanordnung verwendet einen festen Demo-Akteur und implementiert keine Anmeldung. Eine produktive Einbindung muss Identität und Berechtigung aus ihrer maßgeblichen Verwaltung beziehen. Die Prüfung eines Kennungsformats ist keine Bestätigung, dass eine Person sich tatsächlich authentifiziert hat.
Auch der Browserzustand muss zum tatsächlichen Anmeldekontext passen. Ein altes Formular aus einer anderen Anmeldung darf nicht unbemerkt als neue Handlung des nächsten Benutzers weiterlaufen. Das Beispiel hat nur seinen festen Demo-Kontext. Für echte Kontowechsel werden Speicherbereich, Abmelden und Wiederaufnahme ausdrücklich entwickelt. Die serverseitige Bereichstrennung ist dafür ein wichtiger Baustein, ersetzt aber keine vollständige Sitzungsverwaltung.
Dieselbe Absicht anhand ihrer fachlichen Werte prüfen
Ein vorhandener Schlüssel darf nicht stillschweigend für andere Angaben wiederverwendet werden. Unser Kern bildet deshalb einen Fingerabdruck aus dem festen Workshopbezeichner und der ganzzahligen Anzahl. Werden bei derselben Vorgangskennung zwei statt eines Platzes angefordert, entsteht ein Konflikt. Die ursprüngliche Vormerkung und ihr Beleg bleiben unverändert. Der Server deutet die Änderung nicht beiläufig als weitere Bestellung.
Die Vergleichsform ist bewusst auf dieses kleine typisierte Wertepaar begrenzt. Die Reihenfolge der JSON-Eigenschaften ist nicht entscheidend. Eine als Text übermittelte Zahl, ein Wahrheitswert oder eine gebrochene Zahl wird dagegen abgewiesen. Es handelt sich nicht um eine allgemeine kanonische Darstellung beliebiger JSON-Dokumente. Der Vertrag benennt genau die Werte und Typen, die für die Handlung Bedeutung besitzen.
Diese Entscheidung unterscheidet sich von einem Vergleich unveränderter Originalbytes bei einer signierten Fremdschnittstelle. Dort können andere Regeln gelten. Für unser Formular ist die fachlich identische Menge im selben Workshop entscheidend. Eine andere Anwendung muss ihre Vergleichsform ebenfalls ausdrücklich festlegen. Unbeabsichtigte Konvertierungen oder ein übermäßig breiter Inhaltsvergleich können sonst berechtigte Wiederholungen ablehnen oder tatsächlich geänderte Absichten verbergen.
Platzprüfung und Beleg gemeinsam abschließen
Vor der Verarbeitung beginnt der Kern eine unmittelbare SQLite-Transaktion. Er liest zunächst einen vorhandenen Vorgangsbeleg. Fehlt dieser, prüft er den Workshop und die bereits vorgemerkten Plätze. Nur bei ausreichender Kapazität wird eine neue Vormerkung gespeichert. Anschließend entsteht der Beleg mit dem ursprünglichen HTTP-Ergebnis. Beides wird gemeinsam bestätigt und bei einem Fehler gemeinsam zurückgesetzt.
Die Kapazitätsentscheidung findet innerhalb derselben Schreibgrenze statt. Zwei unterschiedliche neue Vorgänge dürfen deshalb nicht beide unabhängig dieselben letzten Plätze versprechen. Im ausgeführten Gegenfall fordern zwei PHP-Prozesse jeweils zwei Plätze bei insgesamt drei Plätzen an. Genau einer erhält seine Vormerkung. Der andere erhält die eindeutige Rückmeldung, dass diese Auswahl nicht verfügbar ist. Der gespeicherte Umfang bleibt bei zwei.
Das gilt für den gezeigten Schreibweg in derselben SQLite-Datei. Weitere Änderungen an der Kapazität oder Vormerkungen müssen die maßgeblichen Regeln ebenfalls beachten. Ein zusätzlicher externer Ticketdienst liegt nicht automatisch in derselben Transaktion. Der Beitrag behauptet weder reale Veranstaltungsplätze noch eine allgemeine Genau-einmal-Garantie für fremde Dienste. Sein Nachweis betrifft den eigenen fiktiven Datenbestand und die ausgeführten Zugriffe.
Den vollständigen PHP-Kern lesen
Der folgende Baustein enthält Tabellen, Beispielworkshop und die Verarbeitung. Eine erfolgreiche erste Vormerkung liefert Status 201 und einen gespeicherten Antwortkörper. Eine identische Wiederholung erhält genau diesen ursprünglichen Antwortkörper und denselben Status. Ein getrenntes Kennzeichen zeigt, dass der Beleg wiederverwendet wurde. Der erneute Status ist deshalb keine Behauptung, es sei nochmals eine neue Vormerkung angelegt worden.
Bei einem widersprüchlichen alten Schlüssel entsteht dagegen ein Konflikt. Unpassende Eingaben werden vor der eigentlichen Wirkung zurückgewiesen. Der Test umfasst außerdem einen gezielten Datenbankfehler beim Speichern des Belegs. Die zuvor innerhalb der Transaktion angelegte Vormerkung bleibt danach nicht bestehen. Diese Gegenprobe zeigt konkret, dass die fachliche Wirkung nicht unabhängig von ihrem Wiederholungsbeleg halb gespeichert wird.
<?php
declare(strict_types=1);
function reservationDatabase(string $path): PDO {
$db=new PDO('sqlite:'.$path,null,null,[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
$db->exec('PRAGMA foreign_keys=ON');$db->exec('PRAGMA busy_timeout=5000');
$db->exec('CREATE TABLE IF NOT EXISTS workshops(id TEXT PRIMARY KEY,capacity INTEGER NOT NULL CHECK(capacity>=0))');
$db->exec("INSERT OR IGNORE INTO workshops VALUES('workshop-demo',3)");
$db->exec('CREATE TABLE IF NOT EXISTS reservations(id TEXT PRIMARY KEY,actor TEXT NOT NULL,workshop TEXT NOT NULL REFERENCES workshops(id),quantity INTEGER NOT NULL CHECK(quantity BETWEEN 1 AND 2),operation TEXT NOT NULL,UNIQUE(actor,operation))');
$db->exec('CREATE TABLE IF NOT EXISTS operations(actor TEXT NOT NULL,operation TEXT NOT NULL,fingerprint TEXT NOT NULL,http_status INTEGER NOT NULL,response TEXT NOT NULL,created_at INTEGER NOT NULL,PRIMARY KEY(actor,operation))');
return $db;
}
function reservePlaces(PDO $db,string $actor,string $operation,array $input,int $now): array {
// actor is already authenticated/authorised application context, not a JSON field.
if(!preg_match('/^[a-z][a-z0-9_-]{1,40}$/D',$actor))throw new InvalidArgumentException('Ungültiger Anwendungskontext.');
if(!preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/D',$operation))
return ['http_status'=>400,'body'=>['error'=>'operation_id'],'replayed'=>false];
$keys=array_keys($input);sort($keys);
if($keys!==['quantity','workshop']||!is_string($input['workshop'])||!preg_match('/^[a-z][a-z0-9-]{1,40}$/D',$input['workshop'])
||!is_int($input['quantity'])||$input['quantity']<1||$input['quantity']>2)
return ['http_status'=>422,'body'=>['error'=>'request_contract'],'replayed'=>false];
// Canonical only for this small explicitly typed tuple, not arbitrary JSON.
$fingerprint=hash('sha256',json_encode(['workshop'=>$input['workshop'],'quantity'=>$input['quantity']],JSON_THROW_ON_ERROR));
$db->exec('BEGIN IMMEDIATE');
try {
$find=$db->prepare('SELECT fingerprint,http_status,response FROM operations WHERE actor=? AND operation=?');$find->execute([$actor,$operation]);$old=$find->fetch(PDO::FETCH_ASSOC);
if($old) {
$db->exec('COMMIT');
if(!hash_equals($old['fingerprint'],$fingerprint))return ['http_status'=>409,'body'=>['error'=>'operation_conflict'],'replayed'=>false];
return ['http_status'=>(int)$old['http_status'],'body'=>json_decode($old['response'],true,512,JSON_THROW_ON_ERROR),'replayed'=>true];
}
$query=$db->prepare('SELECT capacity FROM workshops WHERE id=?');$query->execute([$input['workshop']]);$capacity=$query->fetchColumn();
if($capacity===false){$db->exec('COMMIT');return ['http_status'=>404,'body'=>['error'=>'unknown_workshop'],'replayed'=>false];}
$used=$db->prepare('SELECT COALESCE(SUM(quantity),0) FROM reservations WHERE workshop=?');$used->execute([$input['workshop']]);
if((int)$used->fetchColumn()+$input['quantity']>(int)$capacity) {
$status=409;$body=['status'=>'unavailable'];
} else {
$id=bin2hex(random_bytes(16));
$db->prepare('INSERT INTO reservations VALUES(?,?,?,?,?)')->execute([$id,$actor,$input['workshop'],$input['quantity'],$operation]);
$status=201;$body=['status'=>'reserved','reservation_id'=>$id,'quantity'=>$input['quantity']];
}
$db->prepare('INSERT INTO operations VALUES(?,?,?,?,?,?)')->execute([$actor,$operation,$fingerprint,$status,json_encode($body,JSON_THROW_ON_ERROR),$now]);
$db->exec('COMMIT');
return ['http_status'=>$status,'body'=>$body,'replayed'=>false];
}catch(Throwable $error){$db->exec('ROLLBACK');throw $error;}
}
Ein fehlendes eindeutiges Ergebnis bleibt zunächst offen
Die lokale HTTP-Versuchsanordnung speichert eine Vormerkung und sendet anschließend gezielt einmal keine auswertbaren JSON-Daten zurück. Der Browser kann den Erfolg dadurch nicht bestätigen. Er zeigt Ergebnis unklar und bietet Erneut versuchen an. Die Anzahl bleibt gesperrt und eine Aktion zum Beginnen eines weiteren Vorgangs wird noch nicht angeboten. Der unbekannte Ausgang wird nicht als sicher fehlgeschlagene Vormerkung umgedeutet.
Der nächste Versuch verwendet dieselbe Kennung und dieselben übernommenen Angaben. Die Datenbank liefert den bereits vorhandenen Beleg. Es entsteht keine zweite Vormerkung. Diese Rückkehr ist tatsächlich über Browser und PHP ausgeführt. Es wird dabei keine zufällige Internetstörung gemessen. Die nicht auswertbare Antwort entsteht bewusst an einem bekannten Punkt nach dem Datenbankabschluss und belegt genau diesen Wiederaufnahmeweg.
Ein echter Dienst kann eine andere vorübergehende Störung liefern. Wichtig bleibt, dass ein unklarer Ausgang nicht automatisch eine neue Absicht erzeugt. Sonst könnte aus einer vorsichtig gemeinten Wiederholung eine zusätzliche fachliche Wirkung entstehen. Welche Statusabfragen oder Klärungswege die fertige Anwendung zusätzlich anbietet, wird anhand ihrer tatsächlichen Aufgabe entwickelt. Der kleine Entwurf verwendet den sicheren erneuten Aufruf derselben Handlung.
Neuladen erhält den offenen Vorgang
Der Browser speichert Kennung und übernommenen Datenstand vor der Übermittlung in sessionStorage. Nach dem gezielten Antwortproblem wird die Ansicht im Test tatsächlich neu geladen. Der offene Vorgang bleibt erhalten. Die Oberfläche sendet beim Laden nicht automatisch erneut, sondern bietet denselben ausdrücklichen Wiederholungsweg an. Erst dessen Auslösung fragt den vorhandenen Beleg wieder ab.
Dieser Speicher ist an den vorgesehenen Browserkontext gebunden und kein unbegrenztes dauerhaftes Geschäftsarchiv. Andere Fenster, geschlossene Sitzungen oder ausgeschaltete Speicherfunktionen benötigen eine passende Produktentscheidung. Das Beispiel prüft die Vorbereitbarkeit des Speichers und sendet bei einem dortigen Fehler keinen scheinbar sicher vorbereiteten Vorgang ab. Es verspricht keine Wiederherstellung über beliebige Browser oder Geräte hinweg.
Die gespeicherten Angaben besitzen im Versuch keinen vertraulichen Kundeninhalt. Eine reale Anwendung muss Art und Umfang ihres Browserzustands bewusst wählen. Kennung und Auswahl bleiben clientseitig grundsätzlich veränderbar. Der Server prüft deshalb weiterhin Typen, Berechtigung und Vergleichswert. sessionStorage ist hier eine Hilfe zur Wiederaufnahme und kein Schutzmechanismus, der einen ungeprüften Clientzustand vertrauenswürdig machen würde.
Den vollständigen Browserablauf nachvollziehen
Das folgende HTML zeigt die kleine fiktive Vormerkungsfläche. Die Schaltfläche wird erst durch den vorbereiteten Skriptablauf aktiv. Der Entwurf behauptet deshalb keinen vollständigen Ersatzweg ohne JavaScript. Er ist eine bewusst abgegrenzte Anwendungsfläche für die gezeigte Zustandsführung. Eine echte Einbindung kann einen passenden serverseitigen Grundablauf entwickeln, muss dabei aber dieselbe Vorgangsidentität erhalten.
CSS und JavaScript gehören zu demselben ausgeführten Beispiel. Die Oberfläche unterscheidet offene Handlung und autoritatives Ergebnis. Solange die Handlung offen ist, wird kein neuer Schlüssel nebenbei erzeugt. Nach einer eindeutigen Vormerkung oder einer gespeicherten Nichtverfügbarkeit erscheint eine ausdrückliche neue Aktion. Diese Entscheidung verhindert, dass ein gewöhnlicher Fehlerpfad die fachliche Bedeutung der nächsten Schaltflächenbetätigung unbemerkt verändert.
<main><h1>Plätze im Beispielworkshop vormerken</h1>
<p>Fiktiver Workshop mit anfangs drei Plätzen. Dieser Entwurf führt keine reale Buchung aus.</p>
<form id="reservation-form"><label for="quantity">Anzahl der Plätze</label>
<input id="quantity" name="quantity" type="number" min="1" max="2" step="1" required value="1">
<button id="submit" disabled>Vormerken</button></form>
<p id="status" role="status"></p><p id="receipt"></p>
<button id="new-intent" type="button" hidden>Weitere Vormerkung beginnen</button></main>
*{box-sizing:border-box}body{margin:0;background:#f8f2e8;color:#202428;font:18px/1.5 Arial,sans-serif}main{max-width:46rem;margin:2rem auto;padding:2rem;border-top:6px solid #cc0712}h1{font-size:2rem;line-height:1.2}form{display:grid;gap:1rem;max-width:28rem}input,button{font:inherit;min-height:48px;border:1px solid #777;border-radius:4px;padding:.7rem 1rem;max-width:100%}button{background:#c90713;color:white;border-color:#c90713}button:disabled{opacity:.65}#status{font-weight:bold}#receipt{overflow-wrap:anywhere}:focus-visible{outline:3px solid #cd0712;outline-offset:4px}@media(max-width:500px){main{margin:1rem 0;padding:1.2rem}h1{font-size:1.7rem}}@media(prefers-color-scheme:dark){body{background:#1e2225;color:#fbf3e7}:focus-visible{outline-color:#ff9a90}input{background:#fff;color:#202428}}
const form=document.querySelector('#reservation-form'),quantity=document.querySelector('#quantity');
const submit=document.querySelector('#submit'),newIntent=document.querySelector('#new-intent');
const status=document.querySelector('#status'),receipt=document.querySelector('#receipt');
const storageKey='demo-workshop-intent-v1';
let intent=null,busy=false;
try {
const stored=sessionStorage.getItem(storageKey);
if(stored) {
const saved=JSON.parse(stored);
if(typeof saved.operation!=='string'||!/^[-a-f0-9]{36}$/.test(saved.operation)
||saved.payload?.workshop!=='workshop-demo'||!Number.isInteger(saved.payload.quantity)
||saved.payload.quantity<1||saved.payload.quantity>2)throw Error('Invalid saved intent');
intent=saved;quantity.value=String(intent.payload.quantity);quantity.disabled=true;
status.textContent='Offener Vorgang. Erneut versuchen.';submit.textContent='Erneut versuchen';
}
sessionStorage.setItem(storageKey+'-probe','1');sessionStorage.removeItem(storageKey+'-probe');
submit.disabled=false;
}catch{status.textContent='Der Vorgang konnte nicht vorbereitet werden.';}
form.addEventListener('submit',async event=>{
event.preventDefault();if(busy||!form.reportValidity())return;
try {
if(!intent) {
intent={operation:crypto.randomUUID(),payload:{workshop:'workshop-demo',quantity:quantity.valueAsNumber}};
sessionStorage.setItem(storageKey,JSON.stringify(intent));
}
}catch{intent=null;status.textContent='Der Vorgang konnte nicht vorbereitet werden.';return;}
busy=true;submit.disabled=true;quantity.disabled=true;newIntent.hidden=true;
status.textContent='Vormerkung wird geprüft.';receipt.textContent='';
try {
const response=await fetch('reserve.php'+location.search,{method:'POST',headers:{'Content-Type':'application/json','Idempotency-Key':intent.operation},body:JSON.stringify(intent.payload)});
const result=await response.json();
if(response.status===201&&result.status==='reserved'&&result.quantity===intent.payload.quantity
&&/^[a-f0-9]{32}$/.test(result.reservation_id)) {
status.textContent='Vormerkung gespeichert.';receipt.textContent='Vorgang: '+result.reservation_id;
newIntent.textContent='Weitere Vormerkung beginnen';newIntent.hidden=false;
} else if(response.status===409&&result.status==='unavailable') {
status.textContent='Keine passenden Plätze frei. Es wurde nichts vorgemerkt.';
newIntent.textContent='Auswahl ändern';newIntent.hidden=false;
} else throw Error('No authoritative outcome');
}catch{status.textContent='Ergebnis unklar. Erneut versuchen.';}
finally{busy=false;submit.disabled=false;submit.textContent='Erneut versuchen';}
});
newIntent.addEventListener('click',()=>{
if(busy)return;
try{sessionStorage.removeItem(storageKey);}catch{return;}
intent=null;quantity.disabled=false;quantity.value='1';receipt.textContent='';status.textContent='';
submit.textContent='Vormerken';newIntent.hidden=true;quantity.focus();
});
Eine neue Vormerkung ausdrücklich beginnen
Nach einem eindeutigen Ergebnis kann die Person Weitere Vormerkung beginnen wählen. Erst diese Aktion entfernt den bisherigen Browserzustand und gibt die Auswahl wieder frei. Beim nächsten Absenden entsteht eine neue Kennung. Im Test wird danach eine zweite Vormerkung über zwei Plätze angelegt. Zusammen mit der ersten über einen Platz sind die anfänglichen drei Plätze damit belegt.
Die nächste neue Anfrage erhält eine eindeutige Nichtverfügbarkeit. Auch diese Entscheidung wird für ihre Vorgangskennung gespeichert. Wird die Kapazität im separaten Servergegenversuch später erhöht, wird dieselbe alte abgelehnte Absicht nicht rückwirkend zu einer Vormerkung. Ihre Wiederholung liefert ihren ursprünglichen Beleg. Erst eine bewusst neue Handlung kann die neue Situation verwenden.
Ein solches Ergebnis muss zum Produkt passen. Manche Anwendungen wollen eine neue Verfügbarkeitsabfrage vor dem nächsten Versuch anbieten. Andere benötigen zeitlich begrenzte Vormerkungen. Der hier gezeigte Vertrag ist bewusst einfach und enthält weder automatische Ablaufzeit noch Stornierungsprozess. Die Trennung zwischen historischem Verarbeitungsergebnis und späterem aktuellen Bestand bleibt für solche Erweiterungen ausdrücklich zu entwickeln.

83 ausgeführte Bedingungen im Server und Browser
Der Nachweis verbindet PHP 8.4.27 mit Desktop-Edge. Die Serverfälle betreffen erste Wirkung, Wiederholung, geänderte Angaben unter demselben Schlüssel, gleiche Kennung in verschiedenen Akteursbereichen und die gemeinsame Kapazität. Zwei gleichzeitig laufende PHP-Prozesse liefern denselben Beleg für denselben Vorgang. Zwei konkurrierende neue Vorgänge überschreiten die vorhandenen Plätze nicht. Ein gezielter Belegfehler setzt auch die Vormerkung zurück.
Im Browser werden ein kontrolliert verzögerter Doppelklick, die nicht auswertbare Antwort nach Abschluss, tatsächliches Neuladen, erneuter Aufruf und ausdrücklich neue Absicht ausgeführt. Acht reale Browser-POST-Anfragen gehören zu den beiden Darstellungen. Bei 320, 390 und 1440 Pixeln bleibt die Ergebnisseite innerhalb des verfügbaren Platzes. Die Erklärgrafik verwendet echte Ansichten des unklaren und des anschließend bestätigten Zustands.
Unpassende Mengen, zusätzliche Eigenschaften, ungültige Vorgangskennungen und ein unbekannter Workshop werden ebenfalls geprüft. Diese Fälle erzeugen keine zusätzliche Vormerkung. Die 83 Bedingungen sind ein Funktionsnachweis des kleinen Aufbaus. Es gibt keine Lastmessung, keine reale Reservierung und keine vollständige Authentifizierungsfreigabe. Der kontrollierte Datensatz und die tatsächlich verwendeten Quellen bleiben dem Beispiel eindeutig zugeordnet.
Belege, Wiederherstellung und fachliche Erweiterungen planen
Ein Idempotenzbeleg gehört zum Datenstand der Wirkung. Wird eine Sicherung nur teilweise wiederhergestellt oder der Beleg zu früh entfernt, kann eine spätere Wiederholung ihre Identität verlieren. Die Aufbewahrung muss deshalb zum möglichen Wiederholungszeitraum und zur Wiederherstellung passen. Der Versuch entfernt keine Belege automatisch. Eine tatsächliche Anwendung benötigt dafür einen eigenen nachvollziehbaren Lebenszyklus.
Auch zusätzliche Nebenwirkungen brauchen Beachtung. Eine Mailbestätigung oder ein externer Buchungsaufruf wird nicht allein durch die lokale Transaktion mit abgesichert. Dafür sind gesonderte dauerhafte Übergänge sinnvoll. Der Beleg soll genau die bestätigte eigene Wirkung beschreiben und keine fremde Zustellgarantie vortäuschen. Ebenso ersetzt er keine Prüfung, ob eine Person den Vorgang fachlich überhaupt auslösen darf.
Idempotenz ist keine allgemeine Zusammenführung ähnlicher Texte. Zwei identische Auswahlen können zwei ausdrücklich gewünschte Handlungen sein. Der klare Vorgangsvertrag verbindet deshalb Benutzerabsicht, Wiederholungskennung und Serverzustand. Der vollständige Code und die ausgeführten Gegenfälle zeigen diese Verbindung. In der eigenen Anwendung werden ihre Grenzen anschließend an den tatsächlichen fachlichen Vorgang und den realen Betriebsweg angepasst.
Ein POST wird nicht durch seinen Namen wiederholungssicher
Die Beispiele verwenden POST für die Vormerkung. Die HTTP-Methode allein macht eine solche fachliche Änderung nicht automatisch wiederholungssicher. Entscheidend ist der ausdrücklich entwickelte Vertrag aus stabiler Kennung, passenden Eingabewerten, gemeinsamem Datenstand und ursprünglichem Ergebnis. Eine zusätzliche Kopfzeile mit einem Schlüssel wäre ohne diese Verarbeitung nur eine weitere Zeichenfolge. Der Browser kann nicht erzwingen, dass ein beliebiger fremder Endpunkt ihre Bedeutung tatsächlich unterstützt.
Deshalb wird die Fähigkeit über den gesamten konkreten Weg abgenommen. Geht die Kennung an einem Proxy verloren oder legt ein anderer Schreibweg Vormerkungen ohne Beleg an, gelten andere Voraussetzungen als im gezeigten Versuch. Auch ein später geänderter Vergleich der Eingaben kann bisherige Wiederholungen beeinflussen. Der Vertrag muss bei solchen Änderungen erhalten oder bewusst migriert werden. Eine hilfreiche Dokumentation beschreibt daher nicht nur den Namen der Kopfzeile, sondern die tatsächliche fachliche Einheit, den Geltungsbereich und den erwarteten Umgang mit Konflikten und alten Ergebnissen.
Absicht und Ergebnis im Überblick
| Handlung | Ergebnis im Beispiel |
|---|---|
| Gleicher Akteur, Schlüssel und Auswahl | Ursprünglichen Beleg ohne zweite Vormerkung liefern |
| Gleicher Schlüssel mit anderer Auswahl | Konflikt, ursprüngliche Wirkung erhalten |
| Antwort nach Speicherung nicht auswertbar | Offen bleiben und denselben Vorgang wiederholen |
| Ansicht neu laden | Offenen Vorgang erhalten, nichts automatisch absenden |
| Ausdrücklich neue Vormerkung beginnen | Auswahl freigeben und nächsten Vorgang neu identifizieren |
| Mehrere neue Vorgänge bei knapper Kapazität | Gemeinsame Kapazität innerhalb der Transaktion prüfen |
Checkliste für wiederholbare Formularvorgänge
- Die tatsächliche Absicht und ihren Beginn ausdrücklich festlegen.
- Vorgangskennung bei Wiederholung erhalten statt ständig erneuern.
- Auswahl mit der offenen Handlung verbinden und nicht heimlich ändern.
- Schlüssel an den maßgeblichen Benutzer- und Handlungskontext binden.
- Fachliche Vergleichswerte und Typen klar definieren.
- Wirkung, Kapazität und Beleg in derselben passenden Transaktion behandeln.
- Nicht auswertbare Antworten nicht als sichere Wirkungslosigkeit deuten.
- Neuladen und ausdrückliches Beginnen eines weiteren Vorgangs prüfen.
- Konflikte, parallele Prozesse und Fehler beim Beleg tatsächlich ausführen.
- Aufbewahrung, Anmeldung, Ablauf und externe Nebenwirkungen separat entwickeln.
Quellen und Prüfstand
Primärquellen am 09.11.2026 geprüft. Eigener fiktiver Workshop, 83 ausgeführte PHP-/Edge-Bedingungen und acht Browser-POST-Anfragen. Kontrolliert nicht auswertbare Antwort nach Abschluss, keine reale Buchung und keine vollständige Anmeldung implementiert.








