L’evoluzione dell’architettura web: la nostalgia per PHP e l’incubo di CORS

📖 12min read

“All’epoca bastava un solo file…”

Il PHP con cui avevo avuto a che fare all’università era davvero comodo. In un unico file index.php potevi scrivere i tag HTML, aprire in mezzo <?php ?> e inserirci anche il codice per interrogare il database. Non esisteva una vera separazione tra frontend e backend. Bastava dichiarare una variabile per poterla usare ovunque nell’HTML, e praticamente non c’erano errori dovuti alla comunicazione dei dati.

Ma nel momento in cui, sul lavoro, sono passato a uno stack con Vue.js sul frontend e Spring Boot sul backend, è iniziato l’inferno.

“Ho avviato il server Spring in locale, ho aperto anche la schermata di Vue, allora perché i dati non arrivano?”

La console degli strumenti di sviluppo di Chrome era tappezzata di messaggi d’errore rossi.

Access to XMLHttpRequest at ... has been blocked by CORS policy

Che cos’è esattamente questo “CORS” che continua a bloccare i miei dati? E perché abbiamo abbandonato il metodo comodo di un tempo, in cui bastava un solo file, per separarci volontariamente in frontend e backend?

Un tempo vivevano tutti sotto lo stesso tetto. Oggi abitano in case diverse e devono passare attraverso un controllo.

Chi deve cucinare? (SSR vs CSR)

Per capire questo cambiamento, bisogna prima capire chi prepara il “piatto” chiamato pagina web, cioè l’HTML. Ed è proprio qui che sta la differenza tra SSR (Server Side Rendering) e CSR (Client Side Rendering).

1. SSR: un pranzo già pronto (PHP, JSP)

2. CSR: un meal kit consegnato a casa (React, Vue)

[Tip] CSR e SPA non sono esattamente la stessa cosa

Spesso i due termini vengono usati come se fossero sinonimi, ma a rigore non lo sono.

Di solito usiamo la CSR per costruire una SPA. In altre parole, siccome vogliamo evitare lo sfarfallio dovuto ai ricaricamenti completi usando una sola pagina (SPA), scegliamo un approccio in cui è il browser stesso a ridisegnare le parti necessarie (CSR).

Il motivo per cui usiamo Vue.js o React è l’esperienza utente. Per far sì che un sito web si comporti in modo fluido come un’app per smartphone, abbiamo spostato l’atto del “cucinare” dal server al browser.

CORS, il vigilante che blocca gli ospiti indesiderati

Separando frontend (Vue) e backend (Spring), ci siamo ritrovati di fatto con “due case”.

Ed è proprio qui che nasce il problema. Per motivi di sicurezza, il browser web segue una regola di base: “non fidarti troppo facilmente di risorse che arrivano da un’altra Origin”. Questa è la SOP, la Same Origin Policy.

Immagina questo scenario. Io sono connesso a Naver, e da un sito creato da un hacker parte di nascosto una richiesta al server di Naver che dice: “dammi i dati personali di questo utente”. Se il browser non bloccasse una cosa del genere, tutte le mie informazioni verrebbero esposte.

Ecco perché il browser blocca per impostazione predefinita le richieste quando l’origine, cioè dominio o porta, è diversa. Ma per lo sviluppo noi abbiamo volutamente separato le porte. Vogliamo solo usare i nostri dati, e invece il browser, come un vigilante, ci dice: “La tua porta non corrisponde. Accesso negato.” Questa è la vera natura di un errore CORS, cioè Cross-Origin Resource Sharing.

[Code Verification] Rilasciare un lasciapassare

Il modo per risolvere il problema, in realtà, è semplice. Il server, cioè il backend, deve soltanto scrivere un lasciapassare per il browser, il vigilante, dicendo: “Questa persona è un ospite che ho invitato io. Lascialo entrare.”

In Spring Boot, questo lasciapassare può essere rilasciato tramite un semplice file di configurazione.

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. Per tutti i percorsi API
                .allowedOrigins("http://localhost:8080") // 2. Consenti le richieste da questo origin
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 3. Consenti questi tipi di richieste
                .allowCredentials(true); // 4. Cookie e credenziali sono consentiti
    }
}

Analisi:

Una cosa importante: non bisogna aprire tutto con allowedOrigins("*") solo per pigrizia. Sarebbe come lasciare la porta di casa spalancata con un cartello che dice: “Benvenuti, ladri”.

Consiglio pratico: quando usare cosa?

Quindi significa che la CSR, cioè Vue o React, è sempre la risposta giusta? No. Nella pratica bisogna scegliere in base all’obiettivo.

In chiusura: oltre il confine

La vecchia “grande famiglia sotto un unico tetto” dei tempi di PHP era comoda, ma più tutto diventava complesso, più era difficile da gestire. Il modello attuale, con “due famiglie separate” tra frontend e backend, è più fastidioso a causa della comunicazione e del CORS, ma permette a ciascuno di concentrarsi meglio sul proprio ruolo.

Perciò, la prossima volta che ti imbatterai in un errore CORS, prova a non reagire solo con frustrazione. Il browser non ti sta tormentando: sta semplicemente eseguendo un controllo rigoroso per proteggere la tua casa, cioè il tuo server.

Ora il passaggio tra frontend e backend è aperto. I dati possono andare e venire. Ma dove vengono davvero conservati questi dati sul server? Un tempo bastava lanciare una query e recuperarli. In Spring, invece, con cose come JPA ed Entity, sembra quasi che non ti lascino più scrivere SQL direttamente.

La prossima volta vedremo come il “metodo da manuale” della progettazione di database, la normalizzazione, possa diventare un ostacolo nella pratica e perché JPA cerchi con tanta insistenza di nascondere SQL.

Lascia un commento