Ao desenvolver aplicações frontend, é comum enfrentar o problema de CORS (Cross-Origin Reosurce Sharing). O navegador bloqueia requisições para APIs quando há divergência no domínio, porta ou protocolo (HTTP/HTTPS) em relação à aplicação frontend. Além disso, os desenvolvedores frequentemente acabam repetindo o domínio base do backend em várias chamadas, como https://backend.example.com/api/v1/users e https://backend.example.com/api/v1/posts. Ambas as situações podem ser resolvidas de forma elegante utilizando a configuração de proxy.
Ferramentas de build e servidores de desenvolvimento, como Vite e Webpack, possuem suporte nativo para proxies. O proxy intercepta as requisições feitas para um determinado caminho e as redireciona para o endereço real da API. Para o navegador, a requisição parece ser feita para o mesmo domínio, porta e protocolo, eliminando assim os bloqueios de CORS e a necessidade de hardcodar URLs completas.
Abaixo, veremos como configurar o proxy no Vite. No arquivo vite.config.js, podemos definir regras de redirecionamento. Suponha que nossa aplicação frontend esteja rodando em http://localhost:5173 e queremos interceptar todas as requisições que começam com /services, encaminhando-as para um back end em http://localhost:8080. Além disso, assumiremos que o backend não espera o prefixo /services em suas rotas, portanto, precisamos removê-lo dinamicamente.
import { defineConfig } from 'vite';
export default defineConfig({
server: {
proxy: {
'/services': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (route) => route.replace(/^\/services/, ''),
},
},
},
});
Analisando a estrutura de configuração exportada pelo Vite:
- O objeto
serveragrupa as configurações do servidor de desenvolvimento. - Dentro dele, a propriedade
proxyrecebe um objeto onde as chaves são os prefixos de URL a serem interceptados. - A chave
'/services'indica que qualquer requisição iniciada com esse caminho será processada pelas regras definidas.
Dentro do objeto de configuração do proxy, temos as seguintes propriedades:
target: Define o endereço real do backend. O Vite concatena o caminho da requisição a este target. Por exemplo,/services/dataseria inicialmente convertido parahttp://localhost:8080/services/data.changeOrigin: Quando definido comotrue, altera o cabeçalhoOriginda requisição para que corresponda à URL dotarget. Isso é crucial para evitar que o servidor de destino rejeite a requisição por CORS.rewrite: Permite modificar o caminho da URL antes de enviá-la ao target. Como o backend não possui o prefixo/services, usamos uma função com uma expressão regular para substituir essa parte inicial por uma string vazia, transformando/services/dataem/data.
Com essa configuração, o código frontend pode fazer chamadas de forma limpa, sem precisar especificar o protocolo, domínio ou porta do backend:
fetch('/services/users');
Entendendo a função de rewrite em cenários práticos
A função rewrite é extremamante útil para evitar redundância. Se o seu backend já possui uma base path como /api ou /services, você pode configurar o target para incluir esse prefixo e usar o rewrite para removê-lo da requisição original.
Por exemplo, se o backend está em http://www.api-exemplo.com/services e a rota real é /user/profile, você pode configurar o proxy da seguinte forma:
server: {
proxy: {
'/services': {
target: 'http://www.api-exemplo.com/services',
changeOrigin: true,
rewrite: (route) => route.replace(/^\/services/, '')
}
}
}
Isso permite que você faça a requisição no frontend sem repetir o prefixo:
import axios from 'axios';
axios.post('/user/profile', {
username: 'dev_user'
});
Por outro lado, se você optar por não utilizar a função rewrite, o target deve apontar apenas para o domínio raiz, e a requisição frontend deve incluir o prefixo completo:
server: {
proxy: {
'/services': {
target: 'http://www.api-exemplo.com',
changeOrigin: true
}
}
}
E a chamada no frontend seria:
import axios from 'axios';
axios.post('/services/user/profile', {
username: 'dev_user'
});