Rozpoczynając pracę nad aplikacją z wydzielonym frontendem np. w React i backendem np. w SpringBoot prawdopodobnie napotkasz problem próbując te części ze sobą połączyć.
Jeśli będziesz próbował pobrać dane z backandu i nie zakończy się to sukcesem a w konsoli zobaczysz następujący komunikat:
Zablokowano żądanie do zasobu innego pochodzenia: zasady „Same Origin Policy” nie pozwalają wczytywać zdalnych zasobów z „http://localhost:8080/” (brakujący nagłówek CORS „Access-Control-Allow-Origin”). Kod stanu: 404.
Powód jest prosty, twoja aplikacja SpringBoot działa na innym porcie niż twój serwer developerski hostujący frontend w Reakcie. A zgodnie z zabezpieczeniem CORS strona w przeglądarce może pobierać dane tylko z tej domeny na której się sama znajduje.
Zabezpieczenie to jest jak najbardziej potrzebne i w docelowym (produkcyjnym) systemie trzeba zadbać o spełnienie jego wymagań, natomiast podczas prac developerskich trochę nam utrudnia życie.
Teraz pokażę Ci 2 sposoby jak sobie z tym poradzić. Załóżmy że na frontendzie mamy funkcję która chce pobrać dane z backendu:
const getData = async ()=>{
const response = await fetch("http://localhost:8080/hello");
const data = await response.text();
console.log("data", data);
}
Po stronie backendu obsługuje ją kontroler z odpowiednią metodą:
@RestController
public class MainController {
@GetMapping(value="hello")
private String helloData() {
return "Hi full-stack";
}
}
I teraz metoda numer 1. Wystarczy że dodamy do kontrolera adnotację CrossOrigin, po tym powinien wyglądać następująco.
@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
public class MainController {
@GetMapping(value="hello")
private String helloData() {
return "Hi full-stack";
}
}
I już będzie działać, natomiast jest to bardzo liberalna polityka i pozwala zupełnie na wszystko co oczywiście nie ma prawa pozostać w finalnej (produkcyjnej) wersji aplikacji.
Oczywiście można to modyfikować dla konkretnych domen itp. lub usuwać przed wdrożeniem ale dodaje to dodatkowej pracy i łatwo o czymś zapomnieć. Tu wkracza sposób numer 2.
Możemy pozostawić backend bez zmian natomiast dodać proxy do konfiguracji naszego frontendu, modyfikujemy tylko plik package.json a co najlepsze nie trzeba tego zmieniać przed wdrożeniem. Fragment z dodanym proxy będzie wyglądał tak:
...
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:8080",
"eslintConfig": {
...
Od teraz w naszej aplikacji frontendowej powinniśmy odwoływać się do zasobów przez ścieżki względne, co będzie świetnie działało gdy finalnie dodamy nasz frontend do SpringBoota.
const getData = async ()=>{
const response = await fetch("/hello");
const data = await response.text();
console.log("data", data);
}
Jeszcze mała wskazówka – po modyfikacji pliku package.json zrestartuj frontend.
Ja oczywiście preferuję drugi sposób ale wszystko zależy od konkretnej sytuacji więc zdecyduj sam.