Zum Inhalt springen
Server & Hosting

Wenn die Schnittstelle bremst: Fremdsysteme im Seitenaufbau

Wartet der Server im Seitenaufbau auf ein fremdes System, entscheiden Fristen, Zwischenspeicher und Ersatzwerte darüber, ob die Seite steht oder wartet.

15 Min. Lesezeit SchnittstellenServerantwortzeitAusfallsicherheit

Eine Seite kann im Browser vollkommen schlank sein und trotzdem sekundenlang auf das erste Byte warten. Der Grund steht dann nicht im Quelltext, sondern in einer einzigen Zeile, die während des Seitenaufbaus ein fremdes System fragt: die Warenwirtschaft nach dem Bestand, den Versanddienst nach der Laufzeit, die Preispflege nach dem Tagespreis. Solange die Antwort kommt, fällt das niemandem auf. Bleibt sie aus, wartet der Besucher genau so lange, wie es die eingestellte Frist erlaubt - und die ist in den gängigen Laufzeiten großzügiger, als die meisten Teams vermuten. Dieser Beitrag zeigt, welche Fristen dokumentiert voreingestellt sind, wie sich fremde Antworten in zwei Stufen zwischenspeichern lassen und warum ein Ersatzwert in der Regel die bessere Antwort ist als eine Fehlerseite. Wer davor die eigene Serverantwortzeit sauber messen möchte, findet dort die Grundlagen.

Das Wichtigste in Kürze

  • Fremde Aufrufe im Seitenaufbau sind selten sichtbar: Sie stehen in keinem Wasserfall des Browsers, sondern zwischen Anfrage und erstem Byte. Gemessen wird dort nur, wer sie einzeln mit einem Zeitstempel versieht.
  • Die dokumentierten Voreinstellungen sind lang: 60 Sekunden für Datenströme in PHP (php.net), 300 Sekunden für den Verbindungsaufbau von libcurl (curl.se) und 60 Sekunden Lesepause bei einem vorgeschalteten Proxy (nginx.org).
  • Verbindungsfrist und Gesamtfrist sind zwei verschiedene Dinge: Für den gesamten Abruf setzt libcurl ohne eigene Angabe keine Grenze (curl.se). Ein Aufruf kann damit länger laufen, als jede Geduld reicht.
  • Mindestens 90 Prozent der untersuchten Seiten laden mindestens ein fremdes System im Browser (Web Almanac 2025). Was der Server zusätzlich im Hintergrund abruft, taucht in dieser Zählung gar nicht auf.
  • Ein zwischengespeicherter Wert mit zwei Stufen - frisch und noch verwendbar - hält die Seite auch dann bedienbar, wenn das fremde System gerade nicht antwortet (RFC 9111, RFC 5861).
  • Ersatzwert statt Fehlerseite: Wer für jeden fremden Aufruf vorab festlegt, was ohne Antwort angezeigt wird, entscheidet die Frage im Ruhezustand statt im Störungsfall.

Wenn der Server selbst zum Aufrufer wird

In fast jeder gewachsenen Anwendung gibt es Stellen, an denen der eigene Code während des Seitenaufbaus auf eine fremde Antwort wartet. Der Bestand kommt aus der Warenwirtschaft, der Tagespreis aus einer Preispflege, die Versandlaufzeit vom Dienstleister, die Bewertungsdaten aus einem Portal, die Herkunft der Anfrage aus einem Geodienst. Technisch sind das ausgehende Aufrufe des Servers und keine Ressourcen des Browsers. Sie tauchen deshalb in keinem Wasserfall auf, den ein Entwicklerwerkzeug zeigt, und in keiner Liste blockierender Skripte. Sichtbar werden sie ausschließlich in der Zeit vor dem ersten Byte - und dort als eine einzige, wenig aussagekräftige Zahl. Wer wissen will, welcher Aufruf davon wie viel gekostet hat, braucht einen Zeitstempel je Abschnitt im Backend.

Wie verbreitet fremde Systeme sind, lässt sich für die Browserseite beziffern: Der Anteil der Seiten mit mindestens einem fremden Anbieter liegt bei mindestens 90 Prozent (Web Almanac 2025). Diese Zählung erfasst allerdings nur, was der Browser lädt. Ausgehende Aufrufe des Servers stehen in keiner dieser Erhebungen, weil sie von außen nicht messbar sind. Für die Arbeit an der Ladezeit heißt das: Die sichtbare Hälfte ist gut untersucht und lässt sich mit den üblichen Mitteln von überflüssigen Drittanbieterskripten befreien, die unsichtbare Hälfte kennt nur, wer den eigenen Code liest. Genau dort liegt in vielen Projekten der größere Hebel, weil eine langsame fremde Antwort im Seitenaufbau die gesamte Seite blockiert, während ein langsames Skript im Browser lediglich einen Teil der Darstellung verzögert.

Was die Felddaten zur Serverzeit sagen

Im Jahr 2025 erreichten 44 Prozent der mobilen Websites einen guten TTFB, 40 Prozent lagen im Verbesserungsbereich und 17 Prozent fielen in die langsame Gruppe (Web Almanac 2025). Die Schwelle für einen guten Wert liegt bei 0,8 Sekunden. Ein einziger fremder Aufruf, der eine Sekunde braucht, reicht damit aus, um eine Seite aus der ersten in die zweite Gruppe zu schieben - ohne dass sich am Frontend eine einzige Zeile ändert.

Standardfristen sind Ewigkeiten

Die Voreinstellungen der gängigen Laufzeiten stammen aus einer Zeit, in der ein Skript im Hintergrund lief und niemand auf sein Ergebnis wartete. In PHP ist die Frist für Datenströme mit 60 Sekunden voreingestellt (php.net). Sie gilt für alles, was über die Stream-Schicht läuft, also auch für ein schlichtes Auslesen einer fremden Adresse per file_get_contents. Ein negativer Wert bedeutet an dieser Stelle laut Handbuch eine unbegrenzte Wartezeit. Eine Minute ist im Seitenaufbau kein Grenzfall, sondern ein Totalausfall: Kein Besucher und kein Crawler wartet so lange, und der Prozess, der wartet, steht für andere Anfragen nicht zur Verfügung. Wie schnell daraus eine Kettenreaktion entsteht, zeigt sich unter Last besonders deutlich - im Lasttest vor der Hochsaison ist der blockierte Arbeitsprozess eine der häufigsten Ursachen für den plötzlichen Anstieg der Antwortzeiten.

Bei libcurl, der Bibliothek hinter den meisten HTTP-Aufrufen in PHP, sind zwei Fristen sauber getrennt. Für den Verbindungsaufbau nennt das Handbuch 300 Sekunden als eingebauten Standard (curl.se). Für den gesamten Abruf lautet die Voreinstellung 0, und das bedeutet laut Dokumentation, dass die Übertragung durch keine Frist beendet wird (curl.se). Beide Werte sind für Aufrufe gedacht, die in einem Stapellauf stattfinden, nicht für einen Aufruf, an dem eine Seite hängt. Wer sie nicht ausdrücklich setzt, hat keine Frist gewählt, sondern die Entscheidung an eine Bibliothek abgegeben, die von der Seite nichts weiß.

FristVoreinstellungWas sie begrenztRahmen im Seitenaufbau
default_socket_timeout (PHP)60 sWartezeit auf Datenströme der Stream-Schicht1 bis 3 s
max_execution_time (PHP)30 sRechenzeit des Skriptsunverändert lassen, sie ersetzt die Frist am Aufruf nicht
CURLOPT_CONNECTTIMEOUT (libcurl)300 sausschließlich den Verbindungsaufbau0,5 bis 2 s
CURLOPT_TIMEOUT (libcurl)ohne Fristden gesamten Abruf2 bis 5 s, je nach Zweck
proxy_read_timeout (Proxy)60 sdie Pause zwischen zwei Leseschrittenüber der Frist der Anwendung halten

Die linke Hälfte der Tabelle ist dokumentiert, die rechte nicht: Die Werte in der letzten Spalte sind Erfahrungswerte aus Performance-Projekten (Projekterfahrung) und ersetzen keine Messung im eigenen Netz. Ein verbreiteter Irrtum ist außerdem, die Laufzeitgrenze des Skripts fange den Fall schon ab. Sie ist mit 30 Sekunden voreingestellt (php.net) - und in der voreingestellten Zählweise über setitimer(ITIMER_PROF) misst sie auf Nicht-Windows-Systemen Rechenzeit: Systemaufrufe und Datenstromoperationen zählt sie dort nicht mit (php.net). Genau daraus besteht das Warten auf eine fremde Antwort. In dieser Zählweise kann ein Skript deutlich länger an einer Anfrage hängen, als die Laufzeitgrenze vermuten lässt, ohne abgebrochen zu werden. Ist PHP dagegen mit --enable-zend-max-execution-timers übersetzt - seit PHP 8.3.0 die Voreinstellung für ZTS-Baue -, misst die Grenze verstrichene Zeit und die Wartezeit zählt mit (php.net). Welche Zählweise im eigenen Bau greift, ist damit eine Frage der Übersetzungsoptionen, nicht der Konfiguration. Unabhängig davon bleibt die Frist am Aufruf selbst diejenige, die für einen ausgehenden Aufruf in beiden Fällen gilt.

Verbindungsfrist ist nicht Gesamtfrist

Zwischen Anwendung und Besucher steht in der Regel noch ein vorgeschalteter Proxy, und der bringt eigene Fristen mit. Die Lesefrist steht dort bei 60 Sekunden (nginx.org), und die Dokumentation beschreibt präzise, wie sie gemeint ist: Sie gilt zwischen zwei aufeinanderfolgenden Leseschritten und nicht für die Übertragung der gesamten Antwort. Eine Anwendung, die in kleinen Abständen einzelne Bytes schickt, läuft an dieser Frist beliebig lange vorbei. Für den Verbindungsaufbau gilt eine eigene Frist, die laut Dokumentation in der Regel 75 Sekunden nicht überschreiten kann (nginx.org). Die Fristen müssen deshalb von innen nach außen aufsteigen: Die Anwendung bricht den fremden Aufruf ab, bevor der Proxy die Anwendung abbricht, und der Proxy bricht ab, bevor der Browser aufgibt. Wo die Reihenfolge umgekehrt ist, sieht der Besucher eine Fehlerseite des Proxys, während die Anwendung noch arbeitet - und im Protokoll steht dann kein verwertbarer Hinweis auf die Ursache. Eine Serveroptimierung beginnt an dieser Stelle mit einer einzigen Tabelle: welche Frist steht wo.

fremdaufruf.php
<?php
// Jeder fremde Aufruf bekommt eine eigene, kurze Frist.
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER    => true,
    CURLOPT_CONNECTTIMEOUT_MS => 800,   // nur der Verbindungsaufbau
    CURLOPT_TIMEOUT_MS        => 2500,  // der gesamte Abruf
    CURLOPT_FOLLOWLOCATION    => false, // keine unbemerkten Umwege
    CURLOPT_HTTPHEADER        => ['Accept: application/json'],
]);

$antwort = curl_exec($ch);
$dauer   = curl_getinfo($ch, CURLINFO_TOTAL_TIME);
curl_close($ch);

if ($antwort === false) {
    log_stoerung($schluessel, $dauer);
    return ersatzwert($schluessel);     // statt einer Fehlerseite
}

Was eine Frist nicht abfängt

Eine kurze Frist begrenzt den Schaden je Aufruf, sie beseitigt ihn nicht. Drei Fälle bleiben offen: Ein fremdes System, das langsam, aber stetig Daten schickt, läuft an einer reinen Lesefrist vorbei. Ein Wiederholungsversuch nach jedem Fehlschlag vervielfacht die Wartezeit, statt sie zu begrenzen. Und wenn viele Anfragen gleichzeitig warten, sind die Arbeitsprozesse belegt, obwohl jede einzelne Frist eingehalten wird. Zu jeder Frist gehören deshalb eine Obergrenze für Wiederholungen und ein Schalter, der einen dauerhaft gestörten Aufruf für einige Minuten vollständig aussetzt.

Fremde Antworten zwischenspeichern

Der wirksamste Hebel gegen fremde Wartezeit ist, die Antwort nicht bei jedem Seitenaufruf neu zu holen. RFC 9111 beschreibt den Mechanismus im Kern in einem Satz: Eine frische Antwort kann nachfolgende Anfragen bedienen, ohne den Ursprungsserver zu kontaktieren, und verbessert damit die Effizienz. Frisch heißt dabei, dass das Alter der Antwort ihre Frischedauer noch nicht überschritten hat; danach gilt sie als abgestanden. Die entscheidende Frage im Seitenaufbau lautet also nicht, ob zwischengespeichert wird, sondern wie lange ein Wert gelten darf. Ein Bestand darf Sekunden alt sein, ein Versandtarif Stunden, eine Länderliste Tage. Diese Fristen gehören in eine Tabelle und nicht in den Kopf einer einzelnen Entwicklerin - sie sind Teil jeder belastbaren Caching-Strategie.

Für den Störungsfall gibt es eine zweite Stufe. RFC 5861 beschreibt dafür zwei Erweiterungen des Kopffelds Cache-Control. Mit stale-while-revalidate darf ein Cache eine abgestandene Antwort sofort ausliefern, während er sie im Hintergrund erneuert, und verbirgt damit die Latenz vor dem Client. Mit stale-if-error darf er eine abgestandene Antwort ausliefern, wenn ein Fehler auftritt, statt einen harten Fehler zurückzugeben, was die Verfügbarkeit verbessert. Übertragen auf den eigenen Anwendungs-Cache heißt das: Jeder gespeicherte Wert bekommt zwei Zeitangaben. Nach der ersten wird im Hintergrund erneuert, nach der zweiten wird er verworfen. Zwischen beiden liegt der Bereich, in dem eine Störung des fremden Systems für den Besucher unsichtbar bleibt.

zweistufiger-cache.php
<?php
// Zwei Stufen: frisch bis $frisch, notfalls verwendbar bis $verfall.
function fremdwert(string $schluessel, callable $abruf, int $frisch, int $verfall): ?array
{
    $eintrag = cache_get($schluessel);

    if ($eintrag && $eintrag['alter'] < $frisch) {
        return $eintrag['wert'];            // frisch, direkt ausliefern
    }

    try {
        $wert = $abruf();                   // die Frist steckt im Abruf selbst
        cache_set($schluessel, $wert, $verfall);
        return $wert;
    } catch (Throwable $e) {
        log_stoerung($schluessel, $e);

        if ($eintrag && $eintrag['alter'] < $verfall) {
            return $eintrag['wert'];        // abgestanden, aber brauchbar
        }

        return null;                        // den Ersatzwert waehlt der Aufrufer
    }
}

Ersatzwert statt Fehlerseite

Wenn weder ein frischer noch ein abgestandener Wert vorliegt, entscheidet sich, ob die Seite bricht oder nur ärmer wird. RFC 9110 sieht für den Vermittlerfall den Statuscode 504 vor: Er zeigt an, dass ein Server, der als Gateway oder Proxy arbeitet, keine rechtzeitige Antwort von einem vorgelagerten Server erhalten hat, den er für die Anfrage benötigt. Für die eigene Überlastung ist 503 vorgesehen, der eine vorübergehende Überlastung oder eine geplante Wartung anzeigt, die sich nach einiger Zeit voraussichtlich auflöst. Dazu gehört das Kopffeld Retry-After, mit dem der Server angibt, wie lange ein Client vor einer erneuten Anfrage warten sollte. Diese Codes sind für eine Programmierschnittstelle die richtige Antwort. Für eine Seite, die ein Mensch aufruft, sind sie die schlechtere Wahl: Ein fehlender Bestandshinweis ist ein kleiner Mangel, eine Fehlerseite ist ein verlorener Besuch.

  • Bestand: den letzten bekannten Wert zeigen und die Bestellbarkeit erst im Warenkorb verbindlich prüfen.
  • Preis: den Preis aus dem eigenen Datenbestand zeigen und den fremden Tagespreis nur als Ergänzung führen.
  • Versandlaufzeit: die hinterlegte Regellaufzeit zeigen statt einer leeren Zeile.
  • Bewertungsdaten: den Block ausblenden, statt eine leere Hülle mit Platzhaltern zu rendern.
  • Geokennung: auf Standardsprache, Standardwährung und Standardversandort zurückfallen.
  • Zahlarten: die im eigenen System hinterlegten Arten anzeigen und die Freigabe erst im Bestellschritt einholen.

Die Reihenfolge, die sich bewährt hat

Erst jeden fremden Aufruf im Seitenaufbau auflisten, dann jedem eine eigene Frist geben, dann die Antworten zweistufig zwischenspeichern, dann den Ersatzwert festlegen und zuletzt den Aufruf ganz aus dem Seitenaufbau nehmen, wo es fachlich vertretbar ist. Wer mit dem letzten Schritt beginnt, verschiebt die Wartezeit nur in einen Hintergrundprozess, der dann unbeobachtet ausfällt.

Welcher Teil der Seite darf warten?

Die technische Frage nach Fristen und Zwischenspeicher hat eine fachliche Vorstufe, die häufig übersprungen wird: Welcher Teil der Seite rechtfertigt überhaupt, dass auf eine fremde Antwort gewartet wird? Der Preis gehört in der Regel dazu, weil eine falsche Anzeige rechtlich und wirtschaftlich teuer wird. Die Zahl der Bewertungen gehört in der Regel nicht dazu. Diese Einteilung ist keine Entwicklungsentscheidung, sondern eine des Fachbereichs, und sie sollte einmal schriftlich getroffen werden, statt in jedem Störungsfall neu diskutiert zu werden. Der Checkout ist dabei der empfindlichste Bereich, weil dort die meisten fremden Systeme gleichzeitig beteiligt sind und keine Seite aus einem Cache kommt.

Bestand aus der Warenwirtschaft

Der häufigste fremde Aufruf im Seitenaufbau. Ein Wert, der Sekunden alt ist, reicht für die Anzeige. Die verbindliche Prüfung gehört in den Bestellvorgang und nicht auf die Übersichtsseite.

Tagespreis aus der Preispflege

Preise dürfen nicht falsch stehen, also braucht dieser Aufruf eine kurze Frist und den eigenen Datenbestand als Rückfall. Ein Preis aus dem eigenen System ist besser als gar kein Preis.

Laufzeit vom Versanddienst

Die Regellaufzeit steht in der Regel auch im eigenen Tarifwerk. Der fremde Aufruf verfeinert sie, er ersetzt sie nicht - und darf im Störungsfall deshalb ausfallen.

Bewertungsdaten

Eine Anzeige ohne Gewicht für die Kaufentscheidung im Moment des Seitenaufbaus. Ein Block, der bei fehlender Antwort ausgeblendet wird, kostet weniger als eine Seite, die spürbar später erscheint.

Geokennung der Anfrage

Sprache, Währung und Versandort lassen sich vorab aus der hinterlegten Adresse ableiten. Der Rückfall auf die Standardeinstellung ist an dieser Stelle unauffällig und in aller Regel vertretbar.

Zahlarten und Freigaben

Die Liste der Arten kommt aus dem eigenen System, die Freigabe erst im Bestellschritt. Ein fremder Aufruf im Seitenaufbau ist an dieser Stelle fachlich selten nötig.

Am Ende steht ein kurzes Dokument, das für jeden fremden Aufruf vier Angaben nennt: die Frist, die Gültigkeitsdauer im Zwischenspeicher, den Ersatzwert und die Person, die im Störungsfall entscheidet. Dieses Dokument ist die Grundlage jeder Abnahme, weil es die einzige Stelle ist, an der eine Antwort auf die Frage steht, wie sich die Seite ohne das fremde System verhält. In einer technischen Analyse ist diese Liste erfahrungsgemäß der erste Fund. Für Portale hinter einer Anmeldung gilt das verschärft, weil dort kaum eine Seite aus einem Cache kommt - wie sich Tempo hinter dem Login messen lässt, ist ein Thema für sich.

Eine Seite wird nicht dadurch stabil, dass alle fremden Systeme verfügbar sind. Sie wird stabil, wenn für jedes fremde System vorab entschieden ist, was ohne seine Antwort angezeigt wird.

Projekterfahrung aus Performance-Projekten für Shops und Portale

Der Weg dorthin ist unspektakulär: eine Liste der ausgehenden Aufrufe, ein Zeitstempel je Aufruf, eine Frist je Aufruf, eine Gültigkeitsdauer je Wert und ein festgelegter Ersatzwert. Das ist weniger Aufwand als eine Umstellung des Frontends und wirkt an einer Stelle, an der die üblichen Werkzeuge nichts anzeigen. Wer den Verdacht hat, dass die eigene Serverzeit von fremden Antworten bestimmt wird, misst zuerst die Zeit bis zum ersten Byte und zerlegt sie danach in ihre Bestandteile. Erst dann lohnt der Blick auf Datenbankabfragen oder auf ein Caching-Konzept mit Varnish und Redis. Und wenn das eigene Redaktionssystem den Aufruf im Seitenaufbau erzwingt, hilft der Blick auf die Caching-Ebenen des Systems, bevor an den Fristen gedreht wird.

Dieser Artikel basiert auf Daten aus: PHP-Handbuch (Konfiguration von Dateisystem und Laufzeit), libcurl-Dokumentation (CURLOPT_CONNECTTIMEOUT, CURLOPT_TIMEOUT), nginx-Dokumentation (ngx_http_proxy_module), RFC 9110, RFC 9111 und RFC 5861 sowie Web Almanac 2025 (Kapitel Performance und Third Parties).

Verwandte Artikel

Shops & CMS

TYPO3-Performance: Caching und Ladezeit im Griff behalten

Wie der Seiten-Cache in TYPO3 arbeitet, welche Einstellungen ihn aushebeln und wie Cache-Hash, Backends und das Deployment die Ladezeit einer Seite bestimmen.

15 Min. Lesezeit
Core Web Vitals & Messung

Performance-Messung ohne Einwilligung: was zulässig ist

§ 25 TDDDG greift vor der DSGVO: wann eine Vitals-Messung als Zugriff auf das Endgerät gilt, wie eng die Ausnahme ist und was ohne Einwilligung messbar bleibt.

15 Min. Lesezeit
Frontend-Optimierung

Style-Recalculation: wenn CSS erst im Browser bremst

Warum Stilberechnung zur Laufzeit Zeit kostet, wie Selector Stats und Long Animation Frames den Anteil sichtbar machen und welche Eingriffe den Umfang senken.

14 Min. Lesezeit