API-Endpunkt testen: DNS, TLS, Header & CORS

Kernaussage

„Die API ist down“ ist fast nie ein einzelnes Problem. Testen Sie in sechs Schichten (DNS, Port 443, TLS, HTTP-Status, CORS, Payload) und halten Sie bei der ersten fehlschlagenden an. Typische Ursachen sind ein DNS-Eintrag, der sich nie verbreitet hat, ein über Nacht abgelaufenes Zertifikat oder ein fehlender Access-Control-Allow-Origin-Header, der Browser-Aufrufe bricht, während curl problemlos funktioniert.

Jetzt prüfen

Diagramm der sechs Schichten beim Testen eines öffentlichen API-Endpunkts: DNS-Auflösung, Port 443, TLS-Zertifikat, HTTP-Header, CORS und JSON-Payload
Diagramm der sechs Schichten beim Testen eines öffentlichen API-Endpunkts: DNS-Auflösung, Port 443, TLS-Zertifikat, HTTP-Header, CORS und JSON-Payload
Jetzt lesen
  1. Warum „Die API ist down“ nie ein einzelnes Problem ist
  2. Einen echten Endpunkt wählen, den Sie beliebig oft aufrufen dürfen
  3. Schicht 1: Wird der Hostname aufgelöst?
  4. Schicht 2: Ist Port 443 offen?
  5. Schicht 3: Ist das TLS-Zertifikat gültig?
  6. Schicht 4: Die Antwort-Header lesen
  7. So sieht eine gesunde JSON-Antwort aus
  8. Schicht 5: Der Header, der nur Browser-Aufrufe bricht
  9. Die Preflight-Falle: Funktioniert, bis Sie einen Header hinzufügen
  10. Schicht 6: Hat die Payload die erwartete Form?
  11. Symptom → Schicht → Tool
  12. Häufig gestellte Fragen

Warum „Die API ist down“ nie ein einzelnes Problem ist

Wenn ein API-Aufruf fehlschlägt, wird der Fehler, den Ihr Client anzeigt, meist mehrere Schichten über dem erzeugt, was tatsächlich kaputt ist. Ein Browser, der Failed to fetch meldet, kann nicht sagen, ob der Hostname nicht aufgelöst wurde, die TCP-Verbindung abgelehnt wurde, der TLS-Handshake zurückgewiesen wurde oder der Server ein völlig gesundes 200 geliefert hat, das der Browser wegen eines fehlenden CORS-Headers verworfen hat. Alle vier erzeugen dieselbe Meldung.

Hören Sie auf zu raten und gehen Sie den Stack der Reihe nach durch. Jede Schicht ergibt nur Sinn, wenn die darunterliegende erfolgreich war. Die erste fehlschlagende Schicht ist also Ihr eigentlicher Fehler, alles danach ist Rauschen.

Es lohnt sich, sechs Schichten zu prüfen, und zusammen dauert das etwa zwei Minuten:

  • DNS: Wird der Hostname überhaupt zu einer IP aufgelöst?
  • Port 443: Lauscht dort etwas, oder wird die Verbindung abgelehnt oder gefiltert?
  • TLS: Ist das Zertifikat gültig, nicht abgelaufen und mit vollständiger Kette ausgeliefert?
  • HTTP-Status: Was liefert der Server tatsächlich: 200, 401, 429, 503?
  • CORS: Trägt die Antwort die Header, die ein Browser braucht, um Ihnen den Body zu übergeben?
  • Payload: Hat das JSON die Form, die Ihr Code erwartet?

Status und Header eines Endpunkts jetzt prüfen

Einen echten Endpunkt wählen, den Sie beliebig oft aufrufen dürfen

Zum Üben brauchen Sie einen Live-Endpunkt, der echte Daten liefert, keinen API-Key verlangt und Sie nicht per Rate Limit ausbremst, wenn Sie dieselbe Anfrage zwanzigmal senden. Das schließt die meisten naheliegenden Kandidaten aus: Fast jede gängige öffentliche API verlangt inzwischen eine Registrierung und ein Token, sodass eine fehlgeschlagene Anfrage immer auch an Ihren Zugangsdaten liegen könnte statt an der getesteten Schicht.

Die Beispiele unten verwenden die kostenlose Gebetszeiten-API von Waqt Azan (مواقيت الصلاة), einem arabischen Gebetszeiten-Dienst mit mehr als 60.000 Orten in über 100 Ländern. Als Lehr-Endpunkt eignet sie sich aus drei Gründen: Es gibt weder Key noch Auth-Header, sie liefert strukturiertes JSON statt HTML, und sie setzt eine großzügige CORS-Richtlinie. Die curl-Befehle laufen also genau wie geschrieben, und das fetch()-Beispiel funktioniert in der Konsole einer Seite ohne strikte Content-Security-Policy.

Der Endpunkt nimmt Länder- und Städte-Slug direkt im Pfad:

bash
# Prayer times for a city — no API key, no headers required
curl -s https://waqtazan.com/api/v1/timings/saudi-arabia/riyadh

# The same data as a subscribable calendar feed
curl -s https://waqtazan.com/api/v1/ical/saudi-arabia/riyadh.ics

Setzen Sie einen beliebigen Host ein, den Sie tatsächlich debuggen: Die sechs Schichten sind identisch, ob Sie eine öffentliche API, Ihren eigenen Staging-Server oder einen Webhook-Empfänger eines Drittanbieters testen.

Schicht 1: Wird der Hostname aufgelöst?

DNS ist ein häufiger Übeltäter. Ein Eintrag wurde geändert und hat sich nicht verbreitet, ein Wildcard wurde entfernt, oder die API liegt auf einer Subdomain, die nie angelegt wurde.

Lösen Sie den Hostnamen vor allem anderen auf. Liefert dieser Schritt nichts, hilft kein noch so häufiger Neustart Ihrer App: Ihr Client kommt gar nicht so weit, einen Socket zu öffnen.

bash
dig +short waqtazan.com A
nslookup waqtazan.com

# Compare what different resolvers see — catches mid-propagation records
dig +short waqtazan.com A @1.1.1.1
dig +short waqtazan.com A @8.8.8.8

Wenn zwei öffentliche Resolver kurz nach einer Änderung des Eintrags voneinander abweichen, verbreitet er sich noch, und die API wirkt je nach Resolver des jeweiligen Clients zeitweise kaputt (ein CDN mit Geo-Routing kann jedem Resolver dauerhaft eine andere Adresse geben, vergleichen Sie also mit dem Eintrag, den Sie gesetzt haben). Mit einer DNS-Abfrage sehen Sie alle Einträge, und die Verbreitung bei globalen Resolvern prüfen Sie direkt nach einer Änderung im DNS-Propagation-Checker.

Eine leere Antwort entspricht direkt ERR_NAME_NOT_RESOLVED in Chrome und getaddrinfo ENOTFOUND in Node. Alle Lösungen finden Sie in ERR_NAME_NOT_RESOLVED.

Eines brauchen Sie nicht zu beachten: Viele APIs liegen hinter einem CDN, sodass der A-Eintrag auf einen CDN-Edge statt auf den Ursprungsserver zeigt. Das ist normal. Wichtig ist, dass Sie überhaupt eine Antwort bekommen, nicht welche IP es ist.

Schicht 2: Ist Port 443 offen?

Der Hostname wird aufgelöst, also hat etwas eine Adresse. Jetzt klären Sie, ob dort etwas lauscht. Hier trennen Sie drei sehr unterschiedliche Fehler, die Clients gern identisch melden:

  • Offen (Open): Der TCP-Handshake wird abgeschlossen. Weiter zur nächsten Schicht.
  • Abgelehnt (Refused): Der Host hat sofort mit RST geantwortet. Er ist da, aber nichts ist an den Port gebunden, meist ist der Dienst abgestürzt oder nur an localhost gebunden.
  • Gefiltert (Filtered): Die Verbindung hängt bis zum Timeout. Eine Firewall oder Security Group verwirft Pakete stillschweigend, weshalb Ihre Anfrage über eine Minute hängt, bevor sie fehlschlägt (unter macOS 75 Sekunden).
bash
# Time-boxed TCP check: -w limits the connect on Linux; on macOS use -G 5 instead
nc -vz -w 5 waqtazan.com 443

# Or with curl: --connect-timeout caps the connect; 000 means no response came back
curl -s -o /dev/null -w '%{http_code}\n' --connect-timeout 5 https://waqtazan.com/

Eine abgelehnte und eine gefilterte Verbindung brauchen völlig unterschiedliche Lösungen, daher lohnt es sich zu wissen, welche Sie haben. Der Port-Checker unterscheidet beide und testet von außerhalb Ihres Netzwerks, was wichtig ist: Ein Port, der über Ihr Büro-VPN offen ist, kann aus dem öffentlichen Internet per Firewall gesperrt sein.

Wenn curl als Statuscode 000 ausgibt, kam keine HTTP-Antwort zurück. Meist ist die Anfrage in den Schichten 1–3 gescheitert (keine DNS-Antwort, abgelehnter oder gefilterter Port, fehlgeschlagener TLS-Handshake), aber auch ein Server, der die Verbindung annimmt und dann schließt oder nie antwortet, ergibt 000. Mit -v sehen Sie den letzten funktionierenden Schritt. ERR_CONNECTION_REFUSED behandelt den Fall der Ablehnung ausführlich.

Schicht 3: Ist das TLS-Zertifikat gültig?

Port 443 ist offen, aber ein offener Port bedeutet noch keinen funktionierenden HTTPS-Endpunkt. Zertifikate sind ein klassischer Über-Nacht-Ausfall, weil sie planmäßig ablaufen und die Erneuerungsautomatik still fehlschlägt.

Das Zertifikat muss drei Bedingungen gleichzeitig erfüllen: Es ist nicht abgelaufen, sein Name passt zum angefragten Hostnamen, und der Server sendet die vollständige Zwischenzertifikat-Kette. Die dritte ist die heimtückische: Eine unvollständige Kette funktioniert in Browsern oft, weil Chrome ein fehlendes Zwischenzertifikat selbst nachlädt und Firefox sie vorlädt, während Node, Python, Java und OpenSSL-Builds von curl scheitern (das mit macOS ausgelieferte curl nutzt die Apple-Prüfung und kann bestehen). Das ist der Ursprung des klassischen Fehlerberichts „Im Browser läuft es, in Produktion nicht“.

bash
# Expiry dates and subject
echo | openssl s_client -connect waqtazan.com:443 -servername waqtazan.com 2>/dev/null \
  | openssl x509 -noout -subject -dates

# Full chain as presented by the server
openssl s_client -connect waqtazan.com:443 -servername waqtazan.com -showcerts < /dev/null

Zählen Sie die Zertifikate in der -showcerts-Ausgabe. Ein einzelnes Zertifikat bedeutet meist ein fehlendes Zwischenzertifikat. Der SSL-Zertifikat-Checker meldet Ablauf, Kettenvollständigkeit und Hostnamen-Übereinstimmung in einem Durchgang, und was eine SSL-Zertifikatskette ist erklärt, warum das Zwischenzertifikat so wichtig ist.

Lassen Sie -servername stehen: OpenSSL 1.1.1 und neuer setzen SNI aus dem -connect-Hostnamen, das mit macOS ausgelieferte LibreSSL-openssl aber nicht, und bei einer Verbindung zu einer IP-Adresse keine Version. Ohne SNI liefert ein Shared Host sein Standardzertifikat oder bricht, wie Cloudflare, den Handshake ab, und Sie jagen eine Namensabweichung, die es gar nicht gibt.

Schicht 4: Die Antwort-Header lesen

TLS ist in Ordnung, Sie haben also endlich ein echtes HTTP-Gespräch. Lesen Sie jetzt, was der Server tatsächlich gesagt hat, statt was Ihr Client daraus zusammengefasst hat. Gedruckt werden nur die Header: Der Body wird trotzdem heruntergeladen und verworfen, es ist also dasselbe GET, das Ihr Client sendet.

bash
curl -s -D - -o /dev/null https://waqtazan.com/api/v1/timings/egypt/cairo

Lesen Sie zuerst die Statuszeile, dann content-type, dann alles andere. Diese beiden Felder verraten Ihnen, ob die Anfrage erfolgreich war und ob der Body JSON ist, bevor Sie sonst etwas lesen.

So sieht eine gesunde JSON-Antwort aus

Der obige Befehl gegen den Test-Endpunkt lieferte am 27. Oktober 2026 unter anderem diese Header:

HeaderWertWas er Ihnen sagt
HTTP/2200Die Anfrage war erfolgreich, und der Server spricht HTTP/2
content-typeapplication/jsonSie bekommen JSON, keine HTML-Fehlerseite
content-length567Eine echte Payload, kein leerer Body
access-control-allow-origin*Browser dürfen diese Antwort lesen
servercloudflareVor dem Ursprungsserver sitzt ein CDN
alt-svch3=":443"HTTP/3 wird für Folgeanfragen angeboten

Schicht 5: Der Header, der nur Browser-Aufrufe bricht

In dieser Schicht verschwinden Stunden, denn hier sind curl und Browser tatsächlich verschiedener Meinung. CORS wird vom Browser durchgesetzt, nicht vom Server. Fehlt Access-Control-Allow-Origin, liefert der Server trotzdem ein vollständiges, korrektes 200, nur der Browser weigert sich, den Body an Ihr JavaScript zu übergeben.

Das Symptom lautet also: curl funktioniert einwandfrei, Postman funktioniert einwandfrei, und die Browser-Konsole meldet, die Anfrage sei durch die CORS-Richtlinie blockiert worden. Am Server ist nichts falsch. In der Antwort fehlt nur ein Header.

Der Test-Endpunkt liefert access-control-allow-origin: *, weshalb ein einfaches fetch() von jedem Origin aus funktioniert:

javascript
// Run it in the console of a tab on a site without a strict CSP, such as example.com
// (this page's own CSP blocks it). It works there because ACAO is set to *
const r = await fetch('https://waqtazan.com/api/v1/timings/egypt/cairo')
console.log(await r.json())

Die Preflight-Falle: Funktioniert, bis Sie einen Header hinzufügen

Es gibt eine zweite Falle, und dieser Endpunkt zeigt sie schön. Eine einfache Anfrage (ein schlichtes GET ohne eigene Header) gelingt. Sobald Sie aber einen eigenen Header hinzufügen oder mit Content-Type: application/json per POST senden, schickt der Browser zuerst einen OPTIONS-Preflight, und dessen Antwort muss eigene CORS-Header tragen (MDN).

Testen Sie den Preflight separat, denn er ist eine andere Antwort aus einem anderen Codepfad:

bash
curl -s -D - -o /dev/null -X OPTIONS \
  -H 'Origin: https://example.com' \
  -H 'Access-Control-Request-Method: GET' \
  https://waqtazan.com/api/v1/timings/egypt/cairo

Stand 27. Oktober 2026 liefert dieser Preflight ein 200 mit content-type: text/html und überhaupt keinen access-control-allow-origin-Header, sodass eine Browser-Anfrage mit Preflight blockiert würde, obwohl das einfache GET einwandfrei funktioniert.

Genau das ist die Falle: Ihre Integration läuft in der Entwicklung, Sie fügen einen Authorization- oder X-Request-Id-Header hinzu, und sie bricht ohne jede Änderung am Server. Wenn Sie nur öffentliche Daten brauchen, halten Sie die Anfrage einfach, dann funktioniert sie weiter.

Schicht 6: Hat die Payload die erwartete Form?

Die letzte Schicht ist die, die Ihr Code wirklich interessiert. Ein 200 mit gültigem JSON kann Sie trotzdem brechen, wenn ein Feld umbenannt wurde, ein Typ von Zahl zu String wechselte oder ein Zeitstempel in einem Format ankommt, das Sie nicht parsen.

Sehen Sie sich die echte Antwort an, bevor Sie den Parser schreiben. Dieser Endpunkt liefert sowohl formatierte Anzeigezeiten als auch ISO-Zeitstempel, ein Muster, das man übernehmen sollte: Die lokalisierten Strings sind für Menschen, die ISO-Werte für Code:

json
{
  "city": { "slug": "riyadh", "name_ar": "الرياض", "name_en": "Riyadh" },
  "country": "saudi-arabia",
  "date": "2026-10-26",
  "times":    { "fajr": "4:38 ص", "dhuhr": "11:37 ص", "maghrib": "5:17 م" },
  "timesISO": { "fajr": "2026-10-26T01:38:00.000Z", "dhuhr": "2026-10-26T08:37:00.000Z" },
  "method": "umm_al_qura"
}

Parsen Sie immer das maschinenlesbare Feld. Hier ist das timesISO, nie times: Die Anzeige-Strings sind lokalisiert und ändern ihr Format, sobald sich die Locale ändert.

Leiten Sie die Antwort durch jq, um die Struktur schnell zu prüfen: curl -s <url> | jq keys listet die Felder der obersten Ebene auf, und jq '.times' geht ins Detail, ohne dass Sie durch den rohen Body scrollen müssen.

Symptom → Schicht → Tool

Damit springen Sie direkt zur relevanten Schicht, statt jedes Mal alle sechs zu durchlaufen:

Was Sie sehenFehlerhafte SchichtPrüfen mit
ERR_NAME_NOT_RESOLVED, ENOTFOUND1 — DNSDNS-Abfrage
ECONNREFUSED, instant failure2 — PortPort-Checker
Anfrage hängt, dann Timeout2 — Gefilterter PortPort-Checker
CERT_HAS_EXPIRED, UNABLE_TO_VERIFY_LEAF_SIGNATURE3 — TLSSSL-Checker
Läuft im Browser, scheitert in curl oder Node3 — Unvollständige KetteSSL-Checker
401, 429, 5034 — HTTP-StatusHTTP-Header-Checker
Läuft in curl, im Browser blockiert5 — CORSHTTP-Header-Checker
Unexpected token '<', "<!DOCTYPE "... is not valid JSON4 — HTML-FehlerseiteHTTP-Header-Checker
Felder fehlen oder haben den falschen Typ6 — Payloadcurl … | jq

Die Latenz liegt etwas außerhalb dieser Leiter. Wenn alle Schichten bestehen, die Antworten aber langsam sind, messen Sie die Round-Trip-Zeit zum Host mit ping und prüfen mit einem DNS-Geschwindigkeitstest, ob die Namensauflösung selbst der Engpass ist.

Die echten Antwort-Header jedes Endpunkts prüfen

Sehen Sie den genauen Statuscode, den content-type und die CORS-Header, die eine API zurückgibt. Die Anfrage läuft serverseitig, sodass weder Browser-Cache noch Erweiterungen das Ergebnis verfälschen. Kostenlos, ohne Anmeldung.

Quellen

  1. Cross-Origin Resource Sharing (CORS), MDN
  2. Fetch Standard: CORS-safelisted request headers, WHATWG

Häufig gestellte Fragen

Wie teste ich einen API-Endpunkt ohne Postman?

curl deckt für einfache Tests alles ab, was Postman kann. Mit curl -s -D - -o /dev/null <url> sehen Sie nur die Antwort-Header, mit curl -s <url> | jq prüfen Sie den JSON-Body, und curl -s -o /dev/null -w '%{http_code}' gibt nur den Statuscode aus. Für einen schnellen Check ganz ohne Terminal liefert ein Online-HTTP-Header-Checker dieselben Informationen im Browser.

Warum funktioniert meine API in curl, schlägt aber im Browser fehl?

Fast immer CORS. Der Server liefert in beiden Fällen eine gültige Antwort, aber Browser geben den Body nicht an JavaScript weiter, solange die Antwort keinen Access-Control-Allow-Origin-Header enthält, der Ihren Origin erlaubt. curl ignoriert CORS vollständig, weil CORS eine Sicherheitsrichtlinie des Browsers ist, keine des Servers. Fehlt der Header, muss ihn der Server senden: Eine clientseitige Lösung gibt es nicht.

Was bedeutet der Statuscode 000 bei curl?

Es bedeutet, dass nie eine HTTP-Antwort empfangen wurde, es gibt also keinen Statuscode zu melden. Meist trat der Fehler vor HTTP auf: DNS wurde nicht aufgelöst, die TCP-Verbindung wurde abgelehnt oder gefiltert, oder der TLS-Handshake scheiterte. Ein Server, der die Verbindung annimmt und dann schließt oder nie antwortet, ergibt ebenfalls 000. Führen Sie den Befehl daher noch einmal mit -v aus, um den letzten funktionierenden Schritt zu sehen.

Woran erkenne ich, ob eine API für alle oder nur für mich nicht erreichbar ist?

Testen Sie von außerhalb Ihres eigenen Netzwerks. Ein serverseitig laufender Port-Checker und eine DNS-Abfrage nehmen Ihren lokalen Resolver, VPN, die Firmen-Firewall und den Browser-Cache aus der Gleichung. Antwortet der Endpunkt gegenüber einem externen Checker, aber nicht auf Ihrem Rechner, liegt das Problem lokal: typischerweise DNS-Caching oder eine Firewall-Regel.

Warum liefert eine API 200, aber mein JSON-Parser wirft einen Fehler?

Sie erhalten mit ziemlicher Sicherheit HTML mit Status 200. Captive Portals, Proxys und manche Fehlerseiten liefern einen Erfolgscode mit HTML-Body. Prüfen Sie den content-type-Header: Steht dort text/html statt application/json, ist der Body eine Webseite, und der Parse-Fehler ist ein Symptom, nicht die Ursache.

Was ist ein CORS-Preflight, und wann tritt er auf?

Ein Preflight ist eine automatische OPTIONS-Anfrage, die der Browser vor der eigentlichen sendet, wenn die Anfrage nicht „einfach“ ist: Sie nutzt eine andere Methode als GET, HEAD oder POST, setzt eigene Header wie Authorization oder sendet einen anderen Content-Type als Formulardaten oder Klartext (application/json zählt dazu). Die Preflight-Antwort muss selbst CORS-Header enthalten. Deshalb kann eine Integration problemlos laufen, bis Sie einen Auth-Header hinzufügen, und dann ohne Änderung am Server brechen.

Sollte ich das DNS der API mit meinem eigenen oder einem öffentlichen Resolver testen?

Mit beiden, und vergleichen Sie. Der Resolver Ihres Providers liefert womöglich noch lange einen veralteten Cache-Eintrag, nachdem sich der autoritative Eintrag geändert hat. Abfragen an 1.1.1.1 und 8.8.8.8 neben Ihrem Standard-Resolver zeigen, ob es sich um eine Propagationsverzögerung oder um einen tatsächlich fehlenden Eintrag handelt.

Bedeutet ein offener Port 443, dass der HTTPS-Endpunkt funktioniert?

Nein. Ein offener Port bestätigt nur, dass etwas eine TCP-Verbindung angenommen hat. Der TLS-Handshake kann trotzdem scheitern, weil das Zertifikat abgelaufen ist, der Hostname nicht passt oder die Zwischenzertifikat-Kette unvollständig ist. Prüfen Sie das Zertifikat separat, nachdem Sie bestätigt haben, dass der Port offen ist.

Über den Autor

Shaik Vahid

Gründer von DNS Robot. Vahid hat jahrelang im Webhosting-Support Domains, DNS-Einträge, SSL-Zertifikate und E-Mail-Zustellung für Kunden in Ordnung gebracht. Er entwickelt die Tools von DNS Robot und schreibt diese Anleitungen über die Fehler, die Menschen wirklich sehen.

HTTP-Header-Checker

HTTP-Antwort-Header und Sicherheits-Header-Bewertung analysieren