Jak naprawić błędy CORS (i dlaczego się pojawiają)
Błąd CORS oznacza, że Twoja strona internetowa próbowała odczytać odpowiedź z innego originu (innej domeny, portu lub protokołu), a tamten serwer nie wysłał nagłówków zezwalających na to. Przeglądarki blokują odpowiedź, żeby chronić użytkowników. Naprawiasz to na serwerze: zwracasz nagłówek Access-Control-Allow-Origin dla originu Twojej strony i obsługujesz żądania preflight OPTIONS — albo unikasz problemu, wysyłając żądanie przez własny backend na tej samej domenie.
To jeden z najbardziej mylących błędów w tworzeniu stron, bo żądanie często dociera do serwera bez problemu. Ten przewodnik wyjaśnia, co się dzieje, i jak naprawić każdy wariant.
Co oznacza "origin"
Origin to połączenie protokołu, domeny i portu:
| URL | Origin |
|---|---|
https://myapp.com/dashboard | https://myapp.com |
https://api.myapp.com/users | https://api.myapp.com (inna subdomena, czyli inny origin) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (inny port, czyli inny origin) |
Przeglądarki stosują politykę tego samego originu (same-origin policy): JavaScript na stronie może swobodnie odczytywać odpowiedzi ze swojego originu, ale nie z innych. CORS (Cross-Origin Resource Sharing) to mechanizm, dzięki któremu serwer może wyrazić zgodę: "odpowiedzi ode mnie mogą odczytywać strony z tych originów".
Dwie konsekwencje zaskakują ludzi:
- Żądanie często dociera do serwera. CORS zwykle blokuje Twojemu kodowi odczyt odpowiedzi, a nie odebranie żądania przez serwer. POST mógł zostać zapisany, mimo że zobaczyłeś błąd.
- Egzekwują go tylko przeglądarki. curl, Postman i kod po stronie serwera ignorują CORS całkowicie. Dlatego "działa w Postmanie" nic nie mówi o CORS.
Krok 1: Przeczytaj dokładny błąd
Otwórz narzędzia deweloperskie (prawy przycisk → Zbadaj), przejdź do Konsoli i przeczytaj pełny komunikat. Sformułowanie Chrome mówi, z jakim problemem masz do czynienia:
| Komunikat zawiera | Co jest nie tak |
|---|---|
No 'Access-Control-Allow-Origin' header is present | Serwer w ogóle nie wysłał nagłówka albo żądanie zawiodło, zanim dotarło do Twojego kodu CORS (np. 404 lub 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | Serwer zezwala na inny origin niż Twój |
Response to preflight request doesn't pass access control check | Preflight OPTIONS się nie powiódł |
...must not be the wildcard '*' when the request's credentials mode is 'include' | Wysyłasz ciasteczka, a serwer odpowiedział * |
Request header field authorization is not allowed | Serwer nie wymienił tego nagłówka w Access-Control-Allow-Headers |
Następnie otwórz zakładkę Sieć, znajdź nieudane żądanie (i ewentualne żądanie OPTIONS przed nim) i sprawdź jego kod statusu oraz nagłówki odpowiedzi.
Najpierw sprawdź kod statusu. Wiele "błędów CORS" to w rzeczywistości błąd serwera w przebraniu. Jeśli serwer się wysypie albo zwróci 404, jego odpowiedź o błędzie często nie ma nagłówków CORS, więc przeglądarka zgłasza CORS zamiast prawdziwego problemu. Napraw błąd 500 lub 404, a błąd CORS może zniknąć.
Krok 2: Zdecyduj, czy w ogóle powinieneś wywoływać to API z przeglądarki
Zanim dodasz nagłówki, zapytaj: czy przeglądarka powinna w ogóle wywoływać to API bezpośrednio?
- API firmy trzeciej wymagające klucza sekretnego (OpenAI, klucz sekretny Stripe, większość usług mailowych) nigdy nie powinno być wywoływane z przeglądarki. Klucz byłby widoczny dla każdego odwiedzającego. Wywołuj je z backendu, a problem CORS zniknie, bo żądania serwer–serwer nie podlegają CORS. Zobacz jak chronić klucze API.
- API firmy trzeciej, którą kontrolujesz, a które nie wysyła nagłówków CORS, nie da się naprawić po swojej stronie. Wywołuj je z backendu.
- Twoje własne API możesz naprawić, poprawnie je skonfigurowując. Czytaj dalej.
Krok 3: Napraw to na swoim serwerze
Serwer musi dodawać właściwe nagłówki do swoich odpowiedzi, także tych z błędami.
Dla właściwego żądania wyślij:
Access-Control-Allow-Origin: https://myapp.com(dokładny origin frontendu, bez końcowego ukośnika)Vary: Origin, jeśli wartość zależy od tego, który origin pyta
Dla preflight OPTIONS odpowiedz statusem sukcesu (200 lub 204) i:
Access-Control-Allow-Origin: https://myapp.comAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(każdy własny nagłówek, który wysyłasz)- Opcjonalnie
Access-Control-Max-Age: 600, żeby przeglądarka zapamiętała preflight na pewien czas
Większość frameworków ma pakiet lub ustawienie, które to robi. W Express — pakiet cors; w FastAPI — CORSMiddleware; w ASP.NET Core — AddCors; w Spring — @CrossOrigin lub konfiguracja CORS. Typowa konfiguracja w Express:
import cors from "cors";
app.use(cors({
origin: ["https://myapp.com", "http://localhost:5173"],
credentials: true,
}));
Obsługę CORS umieść przed swoimi trasami i uwierzytelnianiem, tak aby żądania preflight (które nie niosą logowania) nie były odrzucane błędem 401.
W narzędziu do budowania z AI opisz konfigurację precyzyjnie:
Frontend pod adresem
https://myapp.comwywołuje API podhttps://api.myapp.comi dostaje "Response to preflight request doesn't pass access control check". Skonfiguruj CORS w API tak, by zezwalało dokładnie nahttps://myapp.comi origin podglądu, zezwalało na GET, POST, PATCH, DELETE z nagłówkami Content-Type i Authorization, obsługiwało OPTIONS przed uwierzytelnianiem i dołączało nagłówki CORS także do odpowiedzi błędów.
Krok 4: Obsłuż ciasteczka i dane uwierzytelniające
Jeśli Twój frontend wysyła ciasteczka (np. sesję logowania) do innego originu, obie strony muszą się zgadzać:
- Frontend ustawia
credentials: "include"wfetchalbowithCredentials: truew axios. - Serwer wysyła
Access-Control-Allow-Credentials: true. - Nagłówek
Access-Control-Allow-Originserwera musi być dokładnym originem, a nie*.
Ciasteczka międzystronowe wymagają też SameSite=None; Secure, a niektóre przeglądarki dodatkowo ograniczają ciasteczka stron trzecich. To kolejny powód, by preferować podejście z kroku 5.
Krok 5: Unikaj CORS dzięki konfiguracji z tej samej domeny
Często najczystszą naprawą jest niewykonywanie żądań między originami w ogóle. Serwuj API z tego samego originu co strona, na przykład pod https://myapp.com/api/...:
- W developmencie większość serwerów deweloperskich potrafi działać jako proxy. Ustawienie
server.proxyw Vite może przekazywać/apido Twojego backendu na innym porcie, więc przeglądarka rozmawia tylko z jednym originem. - Na produkcji kieruj
/apido backendu przez ustawienia rewrite lub proxy hosta albo serwuj frontend i API z jednego serwera.
Frontend wywołuje wtedy ścieżkę względną, np. fetch("/api/orders"). Nie ma żądania między originami, nie ma preflightu między originami i nie ma kłopotów z ciasteczkami. Nie musisz też wpisywać na sztywno domeny API, która różni się między podglądem a produkcją.
Zmień frontend tak, by wywoływał backend ścieżkami względnymi /api zamiast pełnego adresu, i skonfiguruj proxy deweloperskie tak, by /api przekazywało do serwera API. Potem usuń ustawienia CORS, które już nie są potrzebne.
Czego nie robić
mode: "no-cors"wfetch. Niczego nie omija; daje Twojemu kodowi pustą, nieczytelną odpowiedź.- Rozszerzenia przeglądarki wyłączające CORS. Zmieniają tylko Twoją przeglądarkę. Każdy odwiedzający nadal zobaczy błąd.
- Publiczne usługi "proxy CORS" w prawdziwych aplikacjach. Mogą czytać i zmieniać wszystko, co przez nie przechodzi, i potrafią przestać działać.
Access-Control-Allow-Origin: *na API używającym logowania. I tak nie działa z danymi uwierzytelniającymi, a dla prywatnych danych to zły domyślny wybór.- Odbijanie dowolnego nagłówka
Originz włączonymi danymi uwierzytelniającymi. Pozwala dowolnej stronie wysyłać żądania w imieniu zalogowanych użytkowników. Używaj listy dozwolonych.
Typowe przyczyny w aplikacjach tworzonych z AI
| Sytuacja | Naprawa |
|---|---|
| Frontend wywołuje API firmy trzeciej z kluczem sekretnym | Przenieś wywołanie do backendu |
| Działa w podglądzie, nie działa na opublikowanej domenie | Dodaj originy opublikowanej i własnej domeny do listy dozwolonych albo użyj względnych ścieżek /api |
| Błąd tylko przy POST, PUT lub DELETE | Preflight nieobsłużony; dodaj obsługę OPTIONS i dozwolone nagłówki |
| Błąd pojawił się po dodaniu logowania | Dane uwierzytelniające wymagają dokładnego originu i Allow-Credentials |
| "Błąd CORS", ale zakładka Sieć pokazuje 500 | Najpierw napraw błąd serwera |
Adres API zakodowany na sztywno jako localhost | Używaj ścieżek względnych lub ustawienia dla każdego środowiska |
CORS w Mythex
Kiedy projekt Mythex ma stronę i serwer API, oba działają jako usługi w tym samym projekcie, a w podglądzie możesz przełączać się między nimi. Poproszenie agenta, by frontend wywoływał backend przez względną ścieżkę /api, przekazywaną przez proxy w developmencie, pozwala uniknąć większości problemów z CORS. Jeśli jednak naprawdę potrzebujesz wywołań między originami, podaj agentowi dokładny błąd z konsoli i zaangażowane originy. Sprawdź wynik też na opublikowanej aplikacji, bo jej adres różni się od podglądu. Zobacz Aplikacje wieloserwisowe i Backendy API w dokumentacji oraz nasze przewodniki jak debugować aplikację zbudowaną z AI i frontend a backend.
Lista kontrolna CORS
- Przeczytano pełny błąd w konsoli i kod statusu nieudanego żądania
- Wykluczono ukryty błąd 404 lub 500
- API z kluczami sekretnymi wywoływane z backendu, nie z przeglądarki
- Serwer wysyła
Access-Control-Allow-Originz dokładnymi dozwolonymi originami - Preflight
OPTIONSobsłużony z dozwolonymi metodami i nagłówkami, przed uwierzytelnianiem - Nagłówki CORS obecne także w odpowiedziach błędów
- Dane uwierzytelniające: dokładny origin,
Allow-Credentials: true, właściwe ustawienia ciasteczek - Origin podglądu, opublikowanej i własnej domeny objęte konfiguracją albo użyto względnych ścieżek
/api - Bez
no-cors, publicznych proxy ani odbijania dowolnego originu
Pytania
Co oznacza błąd CORS?
Twoja strona, załadowana z jednego originu, próbowała odczytać odpowiedź z innego originu, a odpowiedź tego serwera nie zawierała nagłówków, które na to zezwalają. Przeglądarka blokuje Twojemu kodowi odczyt odpowiedzi. Rozwiązanie leży po stronie serwera albo w tym, jak kierowane jest żądanie, a nie w kodzie frontendu.
Czy mogę naprawić błąd CORS po stronie frontendu?
Nie w porządny sposób. Ustawienia typu mode: 'no-cors' tylko ukrywają odpowiedź przed Twoim kodem. Naprawiasz to, sprawiając, że serwer wysyła właściwy nagłówek Access-Control-Allow-Origin, albo wywołując API z własnego backendu lub proxy z tej samej domeny.
Czy Access-Control-Allow-Origin: * jest bezpieczne?
Jest w porządku dla publicznych danych, które może odczytać każdy, np. publicznego API bez logowania. Nie działa z ciasteczkami ani innymi danymi uwierzytelniającymi, a dla prywatnych API lepiej wymienić dokładne dozwolone originy.
Dlaczego żądanie działa w Postmanie lub curl, ale nie w przeglądarce?
CORS egzekwują wyłącznie przeglądarki. Narzędzia takie jak Postman czy curl go nie stosują, więc żądanie może się tam powieść, a mimo to zostać zablokowane, gdy wykona je JavaScript strony.
Czym jest żądanie preflight?
Przy żądaniach, które nie są proste, na przykład przy POST z JSON-em albo z nagłówkiem Authorization, przeglądarka najpierw wysyła żądanie OPTIONS, pytając serwer, jakie metody i nagłówki są dozwolone. Jeśli to żądanie OPTIONS się nie powiedzie albo nie ma właściwych nagłówków, właściwe żądanie w ogóle nie zostaje wysłane.