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

Diagram sześciu warstw testowania publicznego endpointu API: rozpoznawanie DNS, port 443, certyfikat TLS, nagłówki HTTP, CORS i payload JSON
Diagram sześciu warstw testowania publicznego endpointu API: rozpoznawanie DNS, port 443, certyfikat TLS, nagłówki HTTP, CORS i payload JSON
Zacznij czytać
  1. Dlaczego "API nie działa" to nigdy jeden problem
  2. Wybierz prawdziwy endpoint, który możesz bez obaw odpytywać
  3. Warstwa 1: czy nazwa hosta się rozwiązuje?
  4. Warstwa 2: czy port 443 jest otwarty?
  5. Warstwa 3: czy certyfikat TLS jest ważny?
  6. Warstwa 4: przeczytaj nagłówki odpowiedzi
  7. Jak wygląda zdrowa odpowiedź JSON
  8. Warstwa 5: nagłówek, który psuje tylko wywołania z przeglądarki
  9. Pułapka preflight: działa, dopóki nie dodasz nagłówka
  10. Warstwa 6: czy payload ma oczekiwany kształt?
  11. Objaw → warstwa → narzędzie
  12. 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:

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

Podstaw 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.

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

Jeś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).
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/

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".

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

Policz 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.

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

Najpierw 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łówekWartośćCo to mówi
HTTP/2200Żądanie się powiodło, a serwer obsługuje HTTP/2
content-typeapplication/jsonDostaniesz JSON, a nie stronę błędu HTML
content-length567Prawdziwy payload, a nie pusta treść
access-control-allow-origin*Przeglądarki mogą odczytać tę odpowiedź
servercloudflarePrzed serwerem źródłowym stoi CDN
alt-svch3=":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:

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())

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:

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

Wedł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:

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"
}

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 widziszWarstwa z błędemSprawdź za pomocą
ERR_NAME_NOT_RESOLVED, ENOTFOUND1 — DNSSprawdzanie DNS
ECONNREFUSED, natychmiastowa porażka2 — PortSprawdzanie portów
Żądanie wisi, potem przekroczenie limitu czasu2 — Port filtrowanySprawdzanie portów
CERT_HAS_EXPIRED, UNABLE_TO_VERIFY_LEAF_SIGNATURE3 — TLSSprawdzanie SSL
Działa w przeglądarce, nie działa w curl lub Node3 — Niekompletny łańcuchSprawdzanie SSL
401, 429, 5034 — Status HTTPChecker nagłówków HTTP
Działa w curl, zablokowane w przeglądarce5 — CORSChecker nagłówków HTTP
Unexpected token '<', "<!DOCTYPE "... is not valid JSON4 — Strona błędu HTMLChecker nagłówków HTTP
Brakujące pola lub zły typ6 — Payloadcurl … | 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

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

Najczęściej zadawane pytania

Jak przetestować endpoint API bez Postmana?

curl pokrywa wszystko, co robi Postman przy podstawowych testach. Użyj curl -s -D - -o /dev/null <url>, by zobaczyć same nagłówki odpowiedzi, curl -s <url> | jq, by obejrzeć treść JSON, oraz curl -s -o /dev/null -w '%{http_code}', by wypisać tylko kod statusu. Do szybkiego sprawdzenia bez terminala wystarczy internetowe narzędzie do sprawdzania nagłówków HTTP, które zwraca te same informacje z przeglądarki.

Dlaczego moje API działa w curl, a nie działa w przeglądarce?

Prawie zawsze chodzi o CORS. Serwer w obu przypadkach zwraca poprawną odpowiedź, ale przeglądarki nie udostępniają treści JavaScriptowi, dopóki odpowiedź nie zawiera nagłówka Access-Control-Allow-Origin zezwalającego na Twój origin. curl całkowicie ignoruje CORS, bo CORS to polityka bezpieczeństwa przeglądarki, a nie serwera. Jeśli nagłówka brakuje, musi go wysłać serwer — po stronie klienta nie ma obejścia.

Co oznacza kod statusu 000 zwracany przez curl?

Oznacza, że nie otrzymano żadnej odpowiedzi HTTP, więc nie ma kodu statusu do zgłoszenia. Zwykle awaria nastąpiła przed HTTP: DNS się nie rozwiązał, połączenie TCP zostało odrzucone lub przefiltrowane albo handshake TLS się nie udał. Serwer, który przyjmuje połączenie, a potem je zamyka lub nigdy nie odpowiada, też daje 000, więc uruchom polecenie ponownie z -v, by zobaczyć ostatni krok, który zadziałał.

Jak sprawdzić, czy API nie działa u wszystkich, czy tylko u mnie?

Testuj spoza własnej sieci. Sprawdzanie portów i DNS po stronie serwera eliminuje z równania lokalny resolwer, VPN, firmową zaporę i cache przeglądarki. Jeśli endpoint odpowiada zewnętrznemu narzędziu, ale nie Twojemu komputerowi, problem jest lokalny — zwykle cache DNS lub reguła zapory.

Dlaczego API zwraca 200, a mój parser JSON zgłasza błąd?

Prawie na pewno dostajesz HTML ze statusem 200. Portale przechwytujące (captive portal), proxy i niektóre strony błędów zwracają kod sukcesu z treścią HTML. Sprawdź nagłówek content-type: jeśli mówi text/html zamiast application/json, treść to strona internetowa, a błąd parsowania jest objawem, nie przyczyną.

Czym jest preflight CORS i kiedy występuje?

Preflight to automatyczne żądanie OPTIONS, które przeglądarka wysyła przed właściwym, ilekroć żądanie nie jest „proste”: używa metody innej niż GET, HEAD lub POST, ustawia własne nagłówki, takie jak Authorization, albo wysyła Content-Type inny niż dane formularza lub zwykły tekst (application/json się do tego zalicza). Odpowiedź na preflight musi sama zawierać nagłówki CORS. Dlatego integracja może działać bez zarzutu, dopóki nie dodasz nagłówka autoryzacji, i wtedy przestaje działać bez żadnej zmiany na serwerze.

Czy DNS API testować własnym resolwerem, czy publicznym?

Oboma i porównać wyniki. Resolwer Twojego dostawcy internetu może serwować przestarzały rekord z cache długo po zmianie rekordu autorytatywnego. Odpytanie 1.1.1.1 i 8.8.8.8 obok domyślnego resolwera pokazuje, czy widzisz opóźnienie propagacji, czy naprawdę brakujący rekord.

Czy otwarty port 443 oznacza, że endpoint HTTPS działa?

Nie. Otwarty port potwierdza tylko, że coś przyjęło połączenie TCP. Handshake TLS nadal może się nie udać, bo certyfikat wygasł, nazwa hosta nie pasuje albo łańcuch certyfikatów pośrednich jest niekompletny. Sprawdź certyfikat osobno po potwierdzeniu, że port jest otwarty.

O autorze

Shaik Vahid

Założyciel DNS Robot. Vahid przez lata pracował we wsparciu hostingu, naprawiając klientom domeny, rekordy DNS, certyfikaty SSL i dostarczanie poczty. Tworzy narzędzia DNS Robot i pisze te poradniki na podstawie błędów, które ludzie naprawdę widzą.

Sprawdzanie Nagłówków HTTP

Analizuj nagłówki odpowiedzi HTTP i ocenę nagłówków bezpieczeństwa