« À l’époque, un seul fichier suffisait… »
Le PHP que j’avais utilisé à l’université était vraiment pratique. Dans un seul fichier index.php, on pouvait écrire les balises HTML, ouvrir <?php ?> au milieu et y ajouter directement le code de requête vers la base de données. Il n’y avait pas de séparation nette entre frontend et backend. Une fois une variable déclarée, on pouvait l’utiliser partout dans le HTML, et les erreurs liées à la communication de données étaient pratiquement inexistantes.
Mais quand, dans la pratique, je suis passé à une stack avec Vue.js pour le frontend et Spring Boot pour le backend, l’enfer a commencé.
« J’ai bien lancé le serveur Spring en local, l’interface Vue tourne aussi, alors pourquoi les données n’arrivent-elles pas ? »
La console des outils de développement de Chrome était recouverte de messages d’erreur rouge vif.
Access to XMLHttpRequest at ... has been blocked by CORS policy
Au fond, qu’est-ce que ce « CORS » qui bloque mes données ? Et pourquoi avons-nous abandonné cette méthode si confortable où un seul fichier suffisait, pour nous imposer volontairement la séparation du frontend et du backend ?

Qui doit cuisiner ? (SSR vs CSR)
Pour comprendre ce changement, il faut d’abord comprendre qui prépare le « plat » qu’est une page web, c’est-à-dire le HTML. C’est exactement là que se situe la différence entre SSR (Server Side Rendering) et CSR (Client Side Rendering).
1. SSR : une lunch box déjà prête (PHP, JSP)
2. CSR : un kit repas livré (React, Vue)
[Tip] CSR et SPA ne veulent pas exactement dire la même chose
On les emploie souvent comme s’ils étaient interchangeables, mais à strictement parler, ce n’est pas le cas.
En pratique, on utilise généralement le CSR pour construire une SPA. Autrement dit, comme on veut éviter le clignotement des rechargements complets en utilisant une seule page (SPA), on choisit une méthode où le navigateur redessine lui-même les parties nécessaires (CSR).
Si nous utilisons Vue.js ou React, c’est avant tout pour l’expérience utilisateur. Pour qu’un site web se comporte avec la fluidité d’une application mobile, on a déplacé l’acte de « cuisiner » du serveur vers le navigateur.

CORS, le vigile qui bloque les invités indésirables
En séparant le frontend (Vue) et le backend (Spring), nous nous sommes retrouvés avec « deux maisons ».
Et c’est là que le problème apparaît. Pour des raisons de sécurité, le navigateur web suit une règle de base : « il ne faut pas faire confiance trop facilement à des ressources venant d’une autre Origin ». C’est la SOP, la Same Origin Policy.
Imaginez : je suis connecté à Naver, et depuis un site créé par un hacker, une requête secrète part vers le serveur de Naver pour dire « donne-moi les informations personnelles de cet utilisateur ». Si le navigateur ne bloquait pas cela, toutes mes données seraient exposées.
C’est pourquoi le navigateur bloque par défaut les requêtes dès que l’origine, c’est-à-dire le domaine ou le port, diffère. Or, pour le développement, nous avons justement séparé les ports de façon intentionnelle. Nous voulons seulement utiliser nos propres données, mais le navigateur, tel un vigile, nous répond : « votre port ne correspond pas, accès refusé ». Voilà ce qu’est réellement une erreur CORS (Cross-Origin Resource Sharing).
[Code Verification] Délivrer un laissez-passer
La solution est en fait assez simple. Le serveur, donc le backend, doit simplement écrire un laissez-passer au navigateur, le vigile, pour lui dire : « cet utilisateur est un invité que j’ai moi-même convié, laisse-le entrer ».
Dans Spring Boot, ce laissez-passer peut être délivré avec un simple fichier de configuration.
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. Pour tous les chemins API
.allowedOrigins("http://localhost:8080") // 2. Autoriser les requetes depuis cette origine
.allowedMethods("GET", "POST", "PUT", "DELETE") // 3. Autoriser ce type de requetes
.allowCredentials(true); // 4. Les cookies et identifiants peuvent etre inclus
}
}
Analyse :
Il faut toutefois faire attention à ne pas, par paresse, tout ouvrir avec allowedOrigins("*"). Ce serait comme laisser la porte d’entrée grande ouverte avec un panneau « Bienvenue aux voleurs ».
Conseil pratique : quand utiliser quoi ?
Est-ce que cela signifie que le CSR, donc Vue ou React, est toujours la bonne réponse ? Non. En pratique, il faut choisir en fonction de l’objectif.
Pour conclure : franchir la frontière
La « grande famille sous un même toit » de l’époque PHP était confortable, mais plus tout se complexifiait, plus cela devenait difficile à gérer. Aujourd’hui, avec « deux familles séparées » que sont le frontend et le backend, la communication via des sujets comme CORS est plus pénible, mais chacun peut se concentrer sur son propre rôle.
La prochaine fois que vous rencontrerez une erreur CORS, essayez donc de ne pas réagir uniquement avec agacement. Le navigateur n’est pas en train de vous harceler : il effectue simplement un contrôle strict pour protéger votre maison, c’est-à-dire votre serveur.
Maintenant, le passage entre frontend et backend est ouvert. Les données peuvent circuler. Mais où ces données sont-elles réellement stockées côté serveur ? Autrefois, il suffisait d’envoyer une requête SQL et de récupérer ce qu’il fallait. En Spring, avec des notions comme JPA et Entity, on a parfois l’impression qu’on nous empêche d’écrire du SQL directement.
La prochaine fois, nous verrons comment la « méthode canonique » de conception de bases de données, la normalisation, peut devenir un frein en pratique, et pourquoi JPA cherche autant à vous cacher le SQL.