A evolução da arquitetura web: a nostalgia do PHP e o pesadelo do CORS

📖 12min read

“Naquela época, um arquivo só bastava…”

O PHP com que eu trabalhava na faculdade era realmente confortável. Em um único arquivo index.php, dava para colocar as tags HTML, abrir <?php ?> no meio e escrever ali mesmo o código de consulta ao banco de dados. Não existia uma separação clara entre frontend e backend. Bastava declarar uma variável e você podia usá-la em qualquer parte do HTML, e praticamente não havia erros causados por comunicação de dados.

Mas quando, na prática, mudei para uma stack com Vue.js no frontend e Spring Boot no backend, o inferno começou.

“Eu subi o servidor Spring localmente, a tela do Vue também está funcionando, então por que os dados não chegam?”

O console das ferramentas de desenvolvedor do Chrome estava coberto de mensagens de erro em vermelho vivo.

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

Afinal, o que é esse tal de CORS que insiste em bloquear meus dados? E por que abandonamos aquele jeito antigo e confortável, em que um único arquivo resolvia tudo, para separar de propósito frontend e backend?

Antes todos viviam sob o mesmo teto; agora moram em casas diferentes e precisam passar por uma inspeção.

Quem deve cozinhar? (SSR vs CSR)

Para entender essa mudança, primeiro é preciso entender quem prepara o “prato” chamado página web, ou seja, o HTML. É exatamente aí que está a diferença entre SSR (Server Side Rendering) e CSR (Client Side Rendering).

1. SSR: uma marmita pronta (PHP, JSP)

2. CSR: um meal kit entregue em casa (React, Vue)

[Tip] CSR e SPA não são exatamente a mesma coisa

Os dois termos costumam ser usados como se fossem sinônimos, mas, tecnicamente, não são.

Normalmente usamos CSR para construir uma SPA. Em outras palavras: como queremos evitar o piscar causado pelo recarregamento completo da página usando uma única página (SPA), escolhemos uma abordagem em que o próprio navegador redesenha as partes necessárias (CSR).

Usamos Vue.js ou React por causa da experiência do usuário. Para fazer um site se comportar com a fluidez de um app de smartphone, transferimos o ato de “cozinhar” do servidor para o navegador.

CORS, o segurança que barra os visitantes indesejados

Quando frontend (Vue) e backend (Spring) se separam, na prática passamos a ter “duas casas”.

E é aí que o problema aparece. Por razões de segurança, o navegador segue uma regra básica: “não confie com facilidade em recursos vindos de outra Origin”. Isso é a SOP, a Same Origin Policy.

Pense nisso. Eu estou logado no Naver, e um site criado por um hacker envia escondido uma requisição para o servidor do Naver dizendo: “me entregue os dados pessoais deste usuário”. Se o navegador não bloqueasse isso, todas as minhas informações ficariam expostas.

Por isso, o navegador bloqueia por padrão requisições quando a origem, ou seja, domínio ou porta, é diferente. Mas, para desenvolvimento, nós deliberadamente separamos as portas. Só queremos usar nossos próprios dados, e mesmo assim o navegador, como um segurança, responde: “Sua porta não bate. Entrada proibida.” Essa é a verdadeira natureza de um erro de CORS, isto é, Cross-Origin Resource Sharing.

[Code Verification] Emitindo um passe de entrada

A forma de resolver isso é, na verdade, simples. O servidor, ou seja, o backend, só precisa escrever um passe para o navegador, o segurança, dizendo: “Essa pessoa é um convidado que eu mesmo convidei. Pode deixar entrar.”

No Spring Boot, esse passe pode ser emitido com um único arquivo de configuração.

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. Para todas as rotas da API
                .allowedOrigins("http://localhost:8080") // 2. Permitir requisicoes desta origem
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 3. Permitir esses tipos de requisicao
                .allowCredentials(true); // 4. Cookies e credenciais podem ser incluidos
    }
}

Análise:

O ponto de atenção é o seguinte: por preguiça, não abra tudo com allowedOrigins("*"). Isso seria o mesmo que deixar a porta de casa escancarada com uma placa dizendo: “Ladrões, sejam bem-vindos”.

Conselho prático: quando usar o quê?

Então CSR, ou seja, Vue ou React, é sempre a resposta certa? Não. Na prática, a escolha depende do objetivo.

Fechando: cruzando a fronteira

A antiga “grande família sob o mesmo teto” da era do PHP era confortável, mas, quanto mais tudo se tornava complexo, mais difícil ficava administrar. O modelo atual, com “duas famílias separadas” entre frontend e backend, é mais incômodo por causa de comunicação e CORS, mas permite que cada lado se concentre melhor no seu papel.

Então, da próxima vez que você topar com um erro de CORS, tente não reagir só com irritação. O navegador não está te perseguindo; ele apenas está fazendo uma inspeção rigorosa para proteger a sua casa, isto é, o seu servidor.

Agora o caminho entre frontend e backend está aberto. Os dados podem ir e vir. Mas onde, afinal, esses dados ficam armazenados no servidor? Antigamente bastava disparar uma query e buscar o que fosse necessário. No Spring, porém, coisas como JPA e Entity dão a impressão de que escrever SQL diretamente já não é mais permitido.

Na próxima vez, vamos ver como a “forma de manual” de projetar bancos de dados, a normalização, pode na prática acabar atrapalhando e por que o JPA tenta tanto esconder o SQL de você.

Deixe um comentário