„Damals hat eine einzige Datei gereicht …“
PHP, mit dem ich im Studium gearbeitet hatte, war wirklich bequem. In eine einzige index.php-Datei konnte man HTML-Tags schreiben, dazwischen <?php ?> öffnen und direkt den Code für Datenbankabfragen einfügen. Es gab keine klare Trennung zwischen Frontend und Backend. Wenn man eine Variable deklarierte, konnte man sie überall im HTML verwenden, und Fehler bei der Datenkommunikation waren praktisch kein Thema.
Aber als ich in der Praxis auf einen Stack mit Vue.js im Frontend und Spring Boot im Backend umstieg, begann die Hölle.
„Der Spring-Server läuft lokal doch eindeutig, die Vue-Oberfläche auch. Warum kommen die Daten dann nicht an?“
Die Konsole in den Chrome-Entwicklertools war komplett mit knallroten Fehlermeldungen überzogen.
Access to XMLHttpRequest at ... has been blocked by CORS policy
Was genau ist dieses „CORS“, das meine Daten blockiert? Und warum haben wir die bequeme Lösung mit nur einer Datei überhaupt aufgegeben, um Frontend und Backend absichtlich zu trennen?

Wer soll kochen? (SSR vs CSR)
Um diesen Wandel zu verstehen, muss man begreifen, wer das „Gericht“ namens Webseite, also HTML, eigentlich zubereitet. Genau darin liegt der Unterschied zwischen SSR (Server Side Rendering) und CSR (Client Side Rendering).
1. SSR: fertig gepackte Lunchbox (PHP, JSP)
2. CSR: Meal-Kit-Lieferung (React, Vue)
[Tip] CSR und SPA sind nicht genau dasselbe
Die Begriffe werden oft durcheinander verwendet, streng genommen sind sie aber nicht identisch.
In der Praxis verwenden wir meist CSR, um eine SPA zu bauen. Anders gesagt: Weil wir mit nur einer Seite ohne ständiges Neuladen arbeiten wollen (SPA), entscheiden wir uns für eine Darstellungsmethode, bei der der Browser die nötigen Teile selbst nachzeichnet (CSR).
Der Grund, warum wir Vue.js oder React einsetzen, ist die User Experience. Damit sich eine Website flüssig wie eine Smartphone-App anfühlt, wurde das „Kochen“ von der Serverseite in den Browser verlagert.

CORS, der Wachmann gegen unerwünschte Besucher
Seit Frontend (Vue) und Backend (Spring) getrennt sind, haben wir praktisch zwei verschiedene Häuser.
Genau hier beginnt das Problem. Der Webbrowser folgt aus Sicherheitsgründen einer Grundregel: „Ressourcen aus einer anderen Origin sollte man nicht blind vertrauen.“ Das ist die SOP, also Same Origin Policy.
Man stelle sich vor: Ich bin bei Naver eingeloggt, und eine Seite eines Hackers schickt heimlich an den Naver-Server die Anfrage „Gib mir die persönlichen Daten dieses Nutzers.“ Würde der Browser das nicht blockieren, wären meine Informationen komplett ausgeliefert.
Deshalb blockiert der Browser standardmäßig Anfragen, sobald sich Origin, also Domain und Port, unterscheiden. Für die Entwicklung haben wir diese Ports aber absichtlich getrennt. Wir wollen nur unsere eigenen Daten nutzen, doch der Browser spielt den Wachmann und sagt: „Ihr Port stimmt nicht überein. Zutritt verboten.“ Genau das ist der Kern eines CORS-Fehlers, also Cross-Origin Resource Sharing.
[Code Verification] Einen Ausweis ausstellen
Die Lösung ist eigentlich einfach. Der Server, also das Backend, stellt dem Browser, also dem Wachmann, einen Ausweis aus: „Diese Person ist mein eingeladener Gast. Bitte hereinlassen.“
In Spring Boot lässt sich dieser Ausweis über eine einzige Konfigurationsdatei ausstellen.
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. Fuer alle API-Pfade
.allowedOrigins("http://localhost:8080") // 2. Anfragen von dieser Adresse zulassen
.allowedMethods("GET", "POST", "PUT", "DELETE") // 3. Solche Anfragen zulassen
.allowCredentials(true); // 4. Cookies und Authentifizierung sind erlaubt
}
}
Analyse:
Wichtig ist nur: Aus Bequemlichkeit sollte man nicht einfach mit allowedOrigins("*") alles freigeben. Das wäre so, als würde man die Haustür sperrangelweit offen lassen und ein Schild aufhängen: „Diebe willkommen.“
Praxisrat: Wann benutzt man was?
Ist CSR, also Vue oder React, damit automatisch immer die richtige Antwort? Nein. In der Praxis muss man abhängig vom Ziel entscheiden.
Zum Schluss: Grenzen überwinden
Die alte PHP-Zeit als „Großfamilie unter einem Dach“ war bequem, wurde aber mit wachsender Komplexität immer schwerer zu handhaben. Die heutige Welt mit „zwei getrennten Haushalten“ aus Frontend und Backend ist wegen Kommunikationsthemen wie CORS zwar lästiger, erlaubt aber, dass sich jede Seite auf ihre eigene Aufgabe konzentriert.
Wenn du also das nächste Mal einen CORS-Fehler siehst, reagiere nicht nur genervt. Der Browser schikaniert dich nicht, sondern führt lediglich eine strenge Kontrolle durch, um dein Haus, also deinen Server, zu schützen.
Jetzt ist der Weg zwischen Frontend und Backend geöffnet. Daten können hin und her fließen. Aber wo werden diese Daten eigentlich auf dem Server gespeichert? Früher konnte ich einfach eine SQL-Abfrage absetzen und die Daten holen. In Spring scheint man wegen Dingen wie JPA und Entity plötzlich kein SQL mehr direkt schreiben zu dürfen.
Nächstes Mal sehen wir uns an, wie der „Lehrbuchstandard“ des Datenbankdesigns, die Normalisierung, in der Praxis zum Stolperstein werden kann und warum JPA so sehr versucht, SQL vor uns zu verstecken.