„Wtedy wystarczał jeden plik…”
PHP, z którym pracowałem na studiach, było naprawdę wygodne. W jednym pliku index.php można było umieścić znaczniki HTML, otworzyć pomiędzy nimi <?php ?> i dopisać tam kod odpytywania bazy danych. Nie było wyraźnego podziału na frontend i backend. Wystarczyło zadeklarować zmienną, by używać jej w dowolnym miejscu w HTML-u, a błędy związane z komunikacją danych praktycznie się nie zdarzały.
Ale kiedy w pracy przesiadłem się na stos technologiczny z Vue.js po stronie frontendu i Spring Boot po stronie backendu, zaczęło się piekło.
„Przecież uruchomiłem lokalnie serwer Springa, ekran Vue też działa, więc dlaczego dane nie przychodzą?”
Konsola w narzędziach deweloperskich Chrome była cała zalana czerwonymi komunikatami o błędach.
Access to XMLHttpRequest at ... has been blocked by CORS policy
Czym właściwie jest ten cały CORS, skoro blokuje moje dane? I dlaczego porzuciliśmy ten wygodny dawny sposób, w którym jeden plik wystarczał do wszystkiego, tylko po to, żeby specjalnie rozdzielić frontend od backendu?

Kto ma gotować? (SSR vs CSR)
Żeby zrozumieć tę zmianę, trzeba najpierw zrozumieć, kto przygotowuje „potrawę” zwaną stroną internetową, czyli HTML. To właśnie na tym polega różnica między SSR (Server Side Rendering) a CSR (Client Side Rendering).
1. SSR: gotowy lunchbox (PHP, JSP)
2. CSR: dostarczony meal kit (React, Vue)
[Tip] CSR i SPA nie znaczą dokładnie tego samego
Często używa się tych terminów zamiennie, ale technicznie nie są one tym samym.
Zwykle używamy CSR po to, żeby zbudować SPA. Innymi słowy, ponieważ chcemy uniknąć migotania związanego z pełnym przeładowaniem strony dzięki jednej stronie (SPA), wybieramy podejście, w którym przeglądarka sama przerysowuje potrzebne fragmenty (CSR).
Powodem, dla którego używamy Vue.js albo Reacta, jest doświadczenie użytkownika. Żeby strona działała płynnie jak aplikacja mobilna, przenieśliśmy „gotowanie” z serwera do przeglądarki.

CORS, ochroniarz blokujący nieproszonych gości
Po rozdzieleniu frontendu (Vue) i backendu (Spring) w praktyce dostaliśmy „dwa domy”.
I właśnie tutaj pojawia się problem. Ze względów bezpieczeństwa przeglądarka kieruje się podstawową zasadą: „nie ufaj zbyt łatwo zasobom pochodzącym z innego Origin”. To właśnie SOP, czyli Same Origin Policy.
Wyobraź sobie taką sytuację. Jestem zalogowany do Naver, a ze strony stworzonej przez hakera po cichu wysyłane jest żądanie do serwera Naver: „daj mi prywatne dane tego użytkownika”. Gdyby przeglądarka tego nie zablokowała, wszystkie moje informacje byłyby wystawione na widok.
Dlatego przeglądarka domyślnie blokuje żądania, kiedy origin, czyli domena albo port, jest inny. A my dla potrzeb developmentu właśnie celowo rozdzieliliśmy porty. Chcemy tylko używać własnych danych, a przeglądarka, niczym ochroniarz, mówi: „Twój port się nie zgadza. Wstęp wzbroniony.” Taka jest prawdziwa natura błędu CORS, czyli Cross-Origin Resource Sharing.
[Code Verification] Wystawienie przepustki
Sposób rozwiązania tego problemu jest w gruncie rzeczy prosty. Serwer, czyli backend, ma po prostu napisać przeglądarce, ochroniarzowi: „to gość, którego sam zaprosiłem, proszę go wpuścić”.
W Spring Boot taką przepustkę można wystawić za pomocą jednego pliku konfiguracyjnego.
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 1. Dla wszystkich sciezek API
.allowedOrigins("http://localhost:8080") // 2. Zezwalaj na zadania z tego adresu
.allowedMethods("GET", "POST", "PUT", "DELETE") // 3. Zezwalaj na te metody zadan
.allowCredentials(true); // 4. Mozna dolaczyc ciasteczka i dane uwierzytelniajace
}
}
Analiza:
Trzeba jednak uważać, żeby z lenistwa nie otworzyć wszystkiego przez allowedOrigins("*"). To byłoby jak zostawienie otwartych na oścież drzwi wejściowych z tabliczką „złodzieje mile widziani”.
Praktyczna rada: kiedy czego używać?
Czy to znaczy, że CSR, czyli Vue albo React, jest zawsze właściwą odpowiedzią? Nie. W praktyce trzeba wybierać zależnie od celu.
Na zakończenie: poza granicą
Dawna „wielka rodzina pod jednym dachem” z czasów PHP była wygodna, ale im bardziej wszystko się komplikowało, tym trudniej było tym zarządzać. Dzisiejszy model „dwóch rozdzielonych rodzin”, frontendu i backendu, jest bardziej uciążliwy przez komunikację i CORS, ale pozwala każdej stronie skupić się na swojej roli.
Więc następnym razem, gdy trafisz na błąd CORS, spróbuj nie reagować wyłącznie z irytacją. Przeglądarka cię nie gnębi. Po prostu przeprowadza rygorystyczną kontrolę, żeby chronić twój dom, czyli twój serwer.
Teraz przejście między frontendem a backendem jest już otwarte. Dane mogą przepływać w obie strony. Ale gdzie właściwie te dane są przechowywane po stronie serwera? Kiedyś wystarczyło rzucić zapytanie i pobrać to, czego się potrzebowało. W Springu, przez takie rzeczy jak JPA czy Entity, ma się czasem wrażenie, że nie wolno już pisać SQL bezpośrednio.
Następnym razem zobaczymy, jak „podręcznikowy” sposób projektowania baz danych, czyli normalizacja, potrafi w praktyce stać się przeszkodą, oraz dlaczego JPA tak bardzo próbuje ukryć przed nami SQL.
1
555
1uY0q9l2w
555
555