Jak przetestować endpoint API: DNS, TLS, nagłówki i CORS
Kluczowy wniosek
"API nie działa" to prawie nigdy jeden problem. Przetestuj je w sześciu warstwach (DNS, port 443, TLS, status HTTP, CORS, payload) i zatrzymaj się na pierwszej, która zawodzi. Zwykle winny jest rekord DNS, który się nie rozpropagował, certyfikat, który wygasł w nocy, albo brakujący nagłówek Access-Control-Allow-Origin, przez który wywołania z przeglądarki padają, choć curl działa bez zarzutu.
Sprawdź teraz

Zacznij czytać
- Dlaczego "API nie działa" to nigdy jeden problem
- Wybierz prawdziwy endpoint, który możesz bez obaw odpytywać
- Warstwa 1: czy nazwa hosta się rozwiązuje?
- Warstwa 2: czy port 443 jest otwarty?
- Warstwa 3: czy certyfikat TLS jest ważny?
- Warstwa 4: przeczytaj nagłówki odpowiedzi
- Jak wygląda zdrowa odpowiedź JSON
- Warstwa 5: nagłówek, który psuje tylko wywołania z przeglądarki
- Pułapka preflight: działa, dopóki nie dodasz nagłówka
- Warstwa 6: czy payload ma oczekiwany kształt?
- Objaw → warstwa → narzędzie
- Najczęściej zadawane pytania
Dlaczego "API nie działa" to nigdy jeden problem
Gdy wywołanie API się nie udaje, błąd pokazany przez klienta powstaje zwykle kilka warstw wyżej niż miejsce faktycznej awarii. Przeglądarka zgłaszająca Failed to fetch nie powie, czy nazwa hosta się nie rozwiązała, połączenie TCP zostało odrzucone, handshake TLS został odrzucony, czy serwer zwrócił całkowicie poprawne 200, które przeglądarka wyrzuciła z powodu braku nagłówka CORS. Wszystkie cztery przypadki dają ten sam komunikat.
Rozwiązaniem jest przestać zgadywać i przejść przez stos po kolei. Każda warstwa ma sens tylko wtedy, gdy ta pod nią działa, więc pierwsza warstwa, która zawodzi, to Twój prawdziwy błąd — wszystko po niej to szum.
Warto sprawdzić sześć warstw i razem zajmuje to około dwóch minut:
- DNS — czy nazwa hosta w ogóle rozwiązuje się na adres IP?
- Port 443 — czy cokolwiek nasłuchuje, czy połączenie jest odrzucane albo filtrowane?
- TLS — czy certyfikat jest ważny, niewygasły i serwowany z kompletnym łańcuchem?
- Status HTTP — co serwer faktycznie zwraca: 200, 401, 429, 503?
- CORS — czy odpowiedź zawiera nagłówki, których przeglądarka potrzebuje, by udostępnić treść?
- Payload — czy JSON ma kształt, jakiego oczekuje Twój kod?
Sprawdź teraz status i nagłówki endpointu
Wybierz prawdziwy endpoint, który możesz bez obaw odpytywać
Do ćwiczeń potrzebujesz działającego endpointu, który zwraca prawdziwe dane, nie wymaga klucza API i nie ograniczy Cię limitem, gdy to samo żądanie wyślesz dwadzieścia razy. To wyklucza większość oczywistych kandydatów — niemal każde popularne publiczne API wymaga dziś formularza rejestracji i tokena, więc nieudane żądanie mogłoby zawsze wynikać z Twoich danych uwierzytelniających, a nie z testowanej warstwy.
Poniższe przykłady używają darmowego API czasów modlitwy z Waqt Azan (مواقيت الصلاة), arabskiego serwisu z czasami modlitw obejmującego ponad 60 000 miejsc w ponad 100 krajach. Nadaje się na endpoint szkoleniowy z trzech powodów: nie ma klucza ani nagłówka autoryzacji, zwraca ustrukturyzowany JSON zamiast HTML i ustawia liberalną politykę CORS — dzięki temu polecenia curl działają dokładnie tak, jak je zapisano, a przykład z fetch() działa w konsoli strony bez restrykcyjnej Content-Security-Policy.
Endpoint przyjmuje slug kraju i miasta bezpośrednio w ścieżce:
# 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.icsPodstaw dowolny host, który faktycznie debugujesz — sześć warstw jest takich samych, niezależnie od tego, czy testujesz publiczne API, własny serwer stagingowy czy odbiornik webhooków firmy trzeciej.
Warstwa 1: czy nazwa hosta się rozwiązuje?
DNS to częsty winowajca. Rekord został zmieniony i jeszcze się nie rozpropagował, usunięto wildcard albo API działa na subdomenie, której nigdy nie utworzono.
Rozwiąż nazwę hosta przed czymkolwiek innym. Jeśli ten krok nic nie zwraca, żadne restartowanie aplikacji nie pomoże — Twój klient nigdy nie dojdzie do otwarcia gniazda.
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.8Jeśli dwa publiczne resolwery się różnią tuż po zmianie rekordu, to nadal się propaguje, a API będzie wyglądać na działające z przerwami, zależnie od tego, w który resolwer trafi dany klient (CDN z geo-routingiem potrafi cały czas podawać każdemu resolwerowi inny adres, więc porównuj z rekordem, który ustawiłeś). Użyj sprawdzania DNS, by zobaczyć pełny zestaw rekordów, albo sprawdź propagację w globalnych resolwerach w narzędziu do sprawdzania propagacji DNS zaraz po zmianie rekordu.
Pusta odpowiedź tutaj odpowiada wprost ERR_NAME_NOT_RESOLVED w Chrome i getaddrinfo ENOTFOUND w Node — pełną listę rozwiązań znajdziesz w artykule ERR_NAME_NOT_RESOLVED.
Jedna rzecz, którą nie warto się przejmować: wiele API stoi za CDN, więc rekord A wskazuje brzeg CDN, a nie serwer źródłowy. To normalne. Liczy się to, że w ogóle dostajesz odpowiedź, a nie jaki to adres IP.
Warstwa 2: czy port 443 jest otwarty?
Nazwa hosta się rozwiązuje, więc coś ma adres. Teraz sprawdź, czy cokolwiek na nim nasłuchuje. Tu rozróżniasz trzy bardzo różne awarie, które klienty chętnie zgłaszają tak samo:
- Otwarty — handshake TCP się kończy. Przejdź do następnej warstwy.
- Odrzucony (refused) — host odpowiedział natychmiastowym RST. Coś tam jest, ale żaden proces nie jest związany z tym portem — zwykle usługa się wywaliła albo nasłuchuje tylko na localhost.
- Filtrowany (filtered) — połączenie wisi aż do przekroczenia limitu czasu. Zapora lub grupa bezpieczeństwa po cichu odrzuca pakiety, dlatego żądanie wisi minutę lub dłużej, zanim się nie powiedzie (75 sekund w macOS).
# 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/Odrzucone i filtrowane połączenie wymagają zupełnie innych napraw, więc warto wiedzieć, które masz. Sprawdzanie portów je rozróżnia i testuje spoza Twojej sieci — co ma znaczenie, bo port otwarty z biurowego VPN może być zablokowany zaporą dla publicznego internetu.
Jeśli curl wypisze 000 jako kod statusu, nie wróciła żadna odpowiedź HTTP. Zwykle żądanie zawiodło w warstwach 1–3 (brak odpowiedzi DNS, port odrzucony lub filtrowany, nieudany handshake TLS), ale serwer, który przyjmuje połączenie, a potem je zamyka albo nigdy nie odpowiada, też daje 000; dodaj -v, by zobaczyć ostatni krok, który zadziałał. Przypadek odrzucenia opisuje szczegółowo ERR_CONNECTION_REFUSED.
Warstwa 3: czy certyfikat TLS jest ważny?
Port 443 jest otwarty, ale otwarty port nie oznacza działającego endpointu HTTPS. Certyfikaty to klasyczna nocna awaria, bo wygasają według harmonogramu, a automatyczne odnawianie psuje się po cichu.
Certyfikat musi spełniać jednocześnie trzy warunki: nie wygasł, jego nazwa pasuje do żądanej nazwy hosta, a serwer wysyła pełny łańcuch certyfikatów pośrednich. Trzeci jest podstępny: niekompletny łańcuch często działa w przeglądarkach, bo Chrome sam pobiera brakujący certyfikat pośredni, a Firefox ma je wstępnie załadowane, natomiast Node, Python, Java i wersje curl zbudowane z OpenSSL zawodzą (curl dostarczany z macOS używa weryfikatora Apple i może przejść). Stąd klasyczne zgłoszenie "u mnie w przeglądarce działa, a na produkcji nie".
# 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/nullPolicz certyfikaty w wyniku -showcerts. Pojedynczy certyfikat zwykle oznacza brakujący certyfikat pośredni. Sprawdzanie certyfikatów SSL w jednym przebiegu pokazuje datę ważności, kompletność łańcucha i zgodność nazwy hosta, a artykuł czym jest łańcuch certyfikatów SSL wyjaśnia, dlaczego certyfikat pośredni jest tak ważny.
Zostaw -servername: OpenSSL 1.1.1 i nowszy uzupełnia SNI z nazwy hosta w -connect, ale LibreSSL openssl dostarczany z macOS tego nie robi, a żadna wersja nie robi tego przy połączeniu z adresem IP. Bez SNI współdzielony host poda swój domyślny certyfikat albo, jak Cloudflare, przerwie handshake, a Ty będziesz gonić niezgodność nazwy, która nie istnieje.
Warstwa 4: przeczytaj nagłówki odpowiedzi
TLS jest w porządku, więc wreszcie masz prawdziwą rozmowę HTTP. Teraz przeczytaj, co serwer faktycznie powiedział, zamiast tego, co streścił Twój klient. Wypisz tylko nagłówki: treść i tak jest pobierana i odrzucana, więc to dokładnie to samo żądanie GET, które wysyła Twój klient.
curl -s -D - -o /dev/null https://waqtazan.com/api/v1/timings/egypt/cairoNajpierw przeczytaj linię statusu, potem content-type, a dopiero potem resztę. Te dwa pola mówią, czy żądanie się powiodło i czy treść to JSON, zanim spojrzysz na cokolwiek innego.
Jak wygląda zdrowa odpowiedź JSON
Uruchomienie powyższego polecenia na testowym endpoincie 27 października 2026 zwróciło m.in. takie nagłówki:
| Nagłówek | Wartość | Co to mówi |
|---|---|---|
HTTP/2 | 200 | Żądanie się powiodło, a serwer obsługuje HTTP/2 |
content-type | application/json | Dostaniesz JSON, a nie stronę błędu HTML |
content-length | 567 | Prawdziwy payload, a nie pusta treść |
access-control-allow-origin | * | Przeglądarki mogą odczytać tę odpowiedź |
server | cloudflare | Przed serwerem źródłowym stoi CDN |
alt-svc | h3=":443" | HTTP/3 jest ogłaszany dla kolejnych żądań |
Warstwa 5: nagłówek, który psuje tylko wywołania z przeglądarki
W tej warstwie znikają godziny, bo to właśnie tu curl i przeglądarka naprawdę się rozmijają. CORS egzekwuje przeglądarka, a nie serwer. Jeśli brakuje Access-Control-Allow-Origin, serwer nadal zwraca kompletne, poprawne 200 — przeglądarka po prostu odmawia przekazania treści Twojemu JavaScriptowi.
Objaw wygląda więc tak: curl działa idealnie, Postman działa idealnie, a konsola przeglądarki mówi, że żądanie zablokowała polityka CORS. Z serwerem nic złego się nie dzieje. W odpowiedzi brakuje po prostu jednego nagłówka.
Testowy endpoint zwraca access-control-allow-origin: *, dlatego zwykłe fetch() z dowolnego origin działa:
// 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())Pułapka preflight: działa, dopóki nie dodasz nagłówka
Jest jeszcze jedna, bardziej podchwytliwa pułapka, a ten endpoint ładnie ją pokazuje. Proste żądanie (zwykły GET bez własnych nagłówków) się udaje. Ale gdy tylko dodasz własny nagłówek albo wyślesz POST z Content-Type: application/json, przeglądarka najpierw wysyła preflight OPTIONS, a odpowiedź na preflight musi zawierać własne nagłówki CORS (MDN).
Testuj preflight osobno, bo to inna odpowiedź z innej ścieżki kodu:
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/cairoWedług stanu z 27 października 2026 ten preflight zwraca 200 z content-type: text/html i w ogóle bez nagłówka access-control-allow-origin, więc żądanie z preflightem z przeglądarki zostałoby zablokowane, mimo że zwykły GET działa bez zarzutu.
To dokładnie ta pułapka: integracja działa w środowisku deweloperskim, dodajesz nagłówek Authorization lub X-Request-Id i przestaje działać, bez żadnej zmiany po stronie serwera. Jeśli potrzebujesz tylko danych publicznych, utrzymaj żądanie jako proste, a będzie działać nadal.
Warstwa 6: czy payload ma oczekiwany kształt?
Ostatnia warstwa to ta, na której naprawdę zależy Twojemu kodowi. Odpowiedź 200 z poprawnym JSON nadal może Cię zepsuć, jeśli pole zmieniło nazwę, typ zmienił się z liczby na tekst albo znacznik czasu przychodzi w formacie, którego nie parsujesz.
Obejrzyj prawdziwą odpowiedź, zanim napiszesz parser. Ten endpoint zwraca zarówno czasy sformatowane do wyświetlania, jak i znaczniki ISO, co jest wzorcem wartym skopiowania — zlokalizowane napisy są dla ludzi, wartości ISO dla kodu:
{
"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"
}Zawsze parsuj pole czytelne maszynowo. Tutaj to timesISO, nigdy times — napisy do wyświetlania są zlokalizowane i zmienią format, gdy tylko zmieni się ustawienie regionalne.
Przepuść odpowiedź przez jq, by szybko obejrzeć strukturę: curl -s <url> | jq keys wypisuje pola najwyższego poziomu, a jq '.times' pozwala zajrzeć do środka bez przewijania surowej treści.
Objaw → warstwa → narzędzie
Użyj tego, by przejść od razu do właściwej warstwy, zamiast za każdym razem przechodzić wszystkie sześć:
| Co widzisz | Warstwa z błędem | Sprawdź za pomocą |
|---|---|---|
ERR_NAME_NOT_RESOLVED, ENOTFOUND | 1 — DNS | Sprawdzanie DNS |
ECONNREFUSED, natychmiastowa porażka | 2 — Port | Sprawdzanie portów |
| Żądanie wisi, potem przekroczenie limitu czasu | 2 — Port filtrowany | Sprawdzanie portów |
CERT_HAS_EXPIRED, UNABLE_TO_VERIFY_LEAF_SIGNATURE | 3 — TLS | Sprawdzanie SSL |
| Działa w przeglądarce, nie działa w curl lub Node | 3 — Niekompletny łańcuch | Sprawdzanie SSL |
401, 429, 503 | 4 — Status HTTP | Checker nagłówków HTTP |
| Działa w curl, zablokowane w przeglądarce | 5 — CORS | Checker nagłówków HTTP |
Unexpected token '<', "<!DOCTYPE "... is not valid JSON | 4 — Strona błędu HTML | Checker nagłówków HTTP |
| Brakujące pola lub zły typ | 6 — Payload | curl … | jq |
Opóźnienia leżą nieco poza tą drabiną. Jeśli wszystkie warstwy przechodzą, a odpowiedzi są wolne, zmierz czas podróży do hosta za pomocą ping i sprawdź, czy wąskim gardłem nie jest samo rozwiązywanie nazw, testem szybkości DNS.
Sprawdź prawdziwe nagłówki odpowiedzi dowolnego endpointu
Zobacz dokładny kod statusu, content-type i nagłówki CORS zwracane przez API. Żądanie wysyłamy po stronie serwera, więc ani cache przeglądarki, ani rozszerzenia nie zniekształcą wyniku. Za darmo, bez rejestracji.
Źródła
Najczęściej zadawane pytania
Jak przetestować endpoint API bez Postmana?
Dlaczego moje API działa w curl, a nie działa w przeglądarce?
Co oznacza kod statusu 000 zwracany przez curl?
Jak sprawdzić, czy API nie działa u wszystkich, czy tylko u mnie?
Dlaczego API zwraca 200, a mój parser JSON zgłasza błąd?
Czym jest preflight CORS i kiedy występuje?
Czy DNS API testować własnym resolwerem, czy publicznym?
Czy otwarty port 443 oznacza, że endpoint HTTPS działa?
Powiązane artykuły
Powiązane narzędzia
Sprawdzanie Nagłówków HTTP
Analizuj nagłówki odpowiedzi HTTP i ocenę nagłówków bezpieczeństwa
Wyszukiwanie DNS
Wszystkie rekordy DNS prosto z serwerów nazw domeny, obok pamięci podręcznej Google i Cloudflare
Sprawdzanie Portów
Testuj łączność portów i dostępność usług
Sprawdzanie Certyfikatu SSL
Weryfikuj ważność certyfikatu SSL i szczegóły bezpieczeństwa
Test Ping
Zmierz ping, jitter i utratę pakietów, sprawdź ping do 34 regionów chmury i pinguj dowolną stronę lub IP z 11 miast



