Seu carrinho está vazio no momento!

Introdução (3 min)
Olá, futuros arquitetos de sistemas! Sejam muito bem-vindos à AULA 36 do nosso intensivo em APIs. Hoje mergulharemos em um tema fundamental que é a espinha dorsal da segurança e interoperabilidade em APIs modernas: o CORS, ou Cross-Origin Resource Sharing.
Imagine o seguinte cenário: você está em uma cidade grande e decide visitar um clube noturno exclusivo. Ao chegar na entrada, o segurança pede sua identificação e verifica uma lista VIP. Se seu nome estiver lá, ou se você for um membro conhecido, a entrada é liberada. Caso contrário, por mais que você tente, o acesso é negado, e você não consegue sequer ver o que acontece lá dentro.
No mundo das APIs, o seu servidor backend é o “clube noturno exclusivo”. As aplicações frontend (websites, aplicativos móveis) são os “visitantes” que tentam acessar os recursos. O CORS é o “segurança” na porta, uma política de segurança implementada pelos navegadores web que define quem está na lista VIP e pode acessar os recursos do seu servidor. Sem ele, os navegadores, por padrão, bloqueiam o acesso entre diferentes “clubes” (origens) para proteger os usuários contra ataques maliciosos.
Por que isso é tão essencial para APIs modernas? No cenário atual, é incomum ter o frontend e o backend hospedados no mesmo domínio. Geralmente, uma aplicação frontend rodando em meusite.com precisa se comunicar com uma API hospedada em api.meusite.com ou até mesmo outrodominio.com. Sem uma configuração explícita de CORS, essa comunicação seria simplesmente impossibilitada, gerando erros frustrantes nos navegadores. Ele viabiliza a integração segura entre diferentes serviços e a construção de arquiteturas distribuídas.
Nesta aula, você aprenderá exatamente o que é CORS, como ele opera nos bastidores, e, o mais valioso, como implementá-lo de forma robusta e segura em suas APIs Node.js com Express. Vamos entender as configurações mais comuns, as melhores práticas corporativas e até como lidar com isso em ambientes de hospedagem como o HostGator Plano M.
Conceito Fundamental (7 min)
O Cross-Origin Resource Sharing (CORS) é um mecanismo de segurança implementado por navegadores web que permite que recursos restritos em uma página web sejam solicitados a partir de um domínio diferente daquele que serviu o primeiro recurso. Ele surge como uma flexibilização controlada da Same-Origin Policy (SOP) — a Política de Mesma Origem.
Terminologia Correta da Indústria
- Origem (Origin): Uma combinação de esquema (protocolo, ex:
http://,https://), host (domínio, ex:www.exemplo.com) e porta (ex::8080). Duas URLs têm a mesma origem se todos esses três componentes forem idênticos. - Same-Origin Policy (SOP): Uma política de segurança fundamental do navegador que restringe como um documento ou script carregado de uma origem pode interagir com um recurso de outra origem. Por exemplo, um script em
siteA.comnão pode, por padrão, fazer uma requisição Ajax parasiteB.com. O CORS vem para relaxar essa restrição de forma controlada. - Requisição Cross-Origin: Uma requisição HTTP feita por um navegador para uma URL que possui uma origem diferente da URL da página web atual.
- Preflight Request: Para certas requisições cross-origin mais “complexas” (que incluem métodos HTTP diferentes de GET, POST para formulários simples, HEAD; que usam headers personalizados, ou Content-Type diferente de
application/x-www-form-urlencoded,multipart/form-dataoutext/plain), o navegador primeiro envia uma requisição OPTIONS, conhecida como “preflight”. Esta requisição serve para verificar com o servidor quais métodos e headers são permitidos para a origem solicitante.
Explicação Detalhada do Conceito Técnico
Quando um navegador detecta uma requisição cross-origin, ele adiciona um cabeçalho Origin com a origem da página solicitante. O servidor, por sua vez, deve responder com um cabeçalho Access-Control-Allow-Origin, indicando qual(is) origem(ns) têm permissão para acessar o recurso. Se o valor do Access-Control-Allow-Origin não corresponder à origem da requisição, ou se não houver tal cabeçalho, o navegador bloqueará a resposta, e a aplicação cliente receberá um erro.
No caso de uma Preflight Request, o navegador envia um método OPTIONS, incluindo cabeçalhos como Access-Control-Request-Method e Access-Control-Request-Headers. O servidor responde a essa requisição OPTIONS com cabeçalhos CORS que informam quais métodos (Access-Control-Allow-Methods), cabeçalhos (Access-Control-Allow-Headers) e tempo de cache (Access-Control-Max-Age) são permitidos. Somente após uma resposta positiva do preflight, o navegador envia a requisição HTTP real.
Casos de Uso Reais em Produção
- Single-Page Applications (SPAs): Aplicativos frontend como React, Angular ou Vue.js, hospedados em um domínio (ex:
app.minhaloja.com), que consomem APIs de backend hospedadas em outro (ex:api.minhaloja.com). - Microsserviços: Um serviço que precisa chamar outro serviço que está em uma origem diferente.
- Integração com serviços de terceiros: Widgets ou scripts de terceiros que precisam fazer requisições para seus próprios servidores a partir do seu domínio.
- APIs Públicas: Quando você desenvolve uma API para ser consumida por qualquer cliente, você geralmente permite CORS de todas as origens (
).
Como isso se Integra com Outras Tecnologias
O CORS não é uma tecnologia isolada; ele é um contrato entre o navegador e o servidor. No Node.js com Express, ele é geralmente implementado através de middlewares, que interceptam as requisições e adicionam os cabeçalhos apropriados às respostas. Servidores web como Nginx ou Apache também podem ser configurados para adicionar cabeçalhos CORS antes que a requisição chegue à sua aplicação Node.js, agindo como um proxy reverso.
Vantagens e Desvantagens
- Vantagens:
- Segurança Aprimorada: Permite que os desenvolvedores definam explicitamente quais origens são permitidas a interagir com seus recursos, protegendo os usuários contra ataques de falsificação de requisição entre sites (CSRF) e outros ataques maliciosos.
- Flexibilidade:Habilita a construção de arquiteturas modernas e distribuídas, onde frontend e backend podem residir em domínios distintos.
- Padrão Aberto: É um padrão W3C, bem documentado e amplamente suportado por todos os navegadores modernos.
- Desvantagens:
- Complexidade de Configuração: Uma configuração inadequada pode levar a vulnerabilidades de segurança (se for muito permissivo) ou a problemas de funcionalidade (se for muito restritivo).
- Erros Frustrantes: Os erros de CORS são notoriamente difíceis de depurar para iniciantes, pois aparecem no console do navegador e não diretamente no log do servidor.
- Overhead para Preflight: Para cada requisição “complexa”, uma requisição OPTIONS adicional é feita, o que pode adicionar um pequeno overhead de rede, embora geralmente otimizado pelo cache do navegador.
Implementação Prática (10 min)
Agora é a hora de transformar teoria em prática. Vamos construir um servidor Express simples e configurar o CORS de várias maneiras, demonstrando as melhores práticas e considerando um ambiente como o HostGator Plano M.
Para começar, certifique-se de ter o Node.js instalado. Crie um novo diretório para o seu projeto e inicialize-o:
mkdir minha-api-cors
cd minha-api-cors
npm init -y
npm install express cors winston dotenv
O pacote cors é um middleware Express oficial que facilita imensamente a configuração do CORS. Usaremos winston para logging profissional e dotenv para gerenciar variáveis de ambiente.
Crie um arquivo chamado server.js (ou app.js) no diretório raiz do seu projeto:
// Importa os módulos essenciais
require('dotenv').config(); // Carrega variáveis de ambiente do arquivo .env
const express = require('express');
const cors = require('cors');
const winston = require('winston'); // Para logging profissional
const path = require('path');
// --- Configuração do Logger Profissional (Winston) ---
// Define o formato do log para incluir timestamp, nível e mensagem
const logFormat = winston.format.printf(({ level, message, timestamp }) => {
return [${timestamp}] ${level.toUpperCase()}: ${message};
});
const logger = winston.createLogger({
level: 'info', // Nível mínimo de log a ser exibido
format: winston.format.combine(
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), // Adiciona timestamp
logFormat // Usa o formato personalizado
),
transports: [
new winston.transports.Console(), // Exibe logs no console
new winston.transports.File({ filename: 'error.log', level: 'error' }), // Logs de erro em arquivo
new winston.transports.File({ filename: 'combined.log' }) // Todos os logs em outro arquivo
],
});
// --- Inicialização do Servidor Express ---
const app = express();
const PORT = process.env.PORT || 3000; // Define a porta, pegando do .env ou usando 3000 como fallback
// --- Configuração de CORS (Variantes) ---
// # Opção 1: CORS Totalmente Aberto (CUIDADO EM PRODUÇÃO!)
// Permite requisições de QUALQUER origem. Útil para APIs públicas ou durante o desenvolvimento.
// Descomente esta linha para usar esta opção.
// app.use(cors());
// logger.warn('CORS configurado para permitir todas as origens (). CUIDADO em produção!');
// # Opção 2: CORS para Origens Específicas (MELHOR PRÁTICA PARA PRODUÇÃO)
// Define uma lista de origens permitidas.
// O ideal é que as origens sejam carregadas de variáveis de ambiente para facilitar a gestão.
const allowedOrigins = process.env.CORS_ALLOWED_ORIGINS
? process.env.CORS_ALLOWED_ORIGINS.split(',') // Divide a string em um array
: ['http://localhost:8080', 'http://127.0.0.1:5500']; // Fallback para desenvolvimento
const corsOptions = {
origin: (origin, callback) => {
// Verifica se a origem da requisição está na lista de origens permitidas.
// Ou se a origem é indefinida (requisições de mesma origem, ou ferramentas como Postman/cURL)
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true); // Permite a requisição
logger.info(CORS: Requisição da origem '${origin || 'N/A'}' permitida.);
} else {
callback(new Error('Não permitido pelo CORS'), false); // Nega a requisição
logger.warn(CORS: Requisição da origem '${origin}' NEGADA.);
}
},
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // Métodos HTTP permitidos
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept'], // Headers permitidos
credentials: true, // Habilita o envio de cookies e cabeçalhos de autorização em requisições cross-origin
optionsSuccessStatus: 200 // Algumas ferramentas legadas esperam 200 para OPTIONS
};
app.use(cors(corsOptions)); // Aplica as opções de CORS configuradas
// # Opção 3: CORS Manual (Para entendimento profundo)
// Se você não quiser usar o pacote 'cors', pode implementar manualmente.
// Isso é mais complexo e o pacote 'cors' é geralmente preferível.
/
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, Accept');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Max-Age', '86400'); // Cache do preflight por 24 horas
// Lida com requisições preflight (OPTIONS)
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});
logger.warn('CORS configurado manualmente. Certifique-se de que a lógica está correta!');
/
// --- Middleware para parsing de JSON no corpo das requisições ---
app.use(express.json());
// --- Rotas da API (Exemplo) ---
// Rota raiz simples
app.get('/', (req, res) => {
logger.info('Requisição recebida na rota /');
res.send('API de CORS Rodando! Acesse /dados para ver os recursos.');
});
// Exemplo de dados (simulando um banco de dados)
const produtos = [
{ id: 1, nome: 'Notebook Gamer', preco: 7500.00 },
{ id: 2, nome: 'Smartphone Ultra', preco: 3200.00 },
{ id: 3, nome: 'Monitor Curvo', preco: 1800.00 }
];
// Rota para obter todos os produtos
app.get('/dados', (req, res) => {
logger.info('Requisição GET /dados recebida.');
res.status(200).json(produtos);
});
// Rota para adicionar um novo produto (exige POST e Content-Type: application/json)
app.post('/dados', (req, res) => {
const { nome, preco } = req.body;
// Validação de entrada robusta (exemplo simples)
if (!nome || typeof nome !== 'string' || !preco || typeof preco !== 'number') {
logger.error('Validação falhou: dados de produto inválidos.');
return res.status(400).json({ mensagem: 'Dados de produto inválidos. Nome e Preço são obrigatórios.' });
}
const novoProduto = {
id: produtos.length + 1,
nome,
preco
};
produtos.push(novoProduto);
logger.info(Produto adicionado: ${JSON.stringify(novoProduto)});
res.status(201).json(novoProduto);
});
// --- Middleware de tratamento de erros global ---
app.use((err, req, res, next) => {
logger.error(Erro inesperado: ${err.stack});
res.status(500).json({ mensagem: 'Ocorreu um erro interno no servidor.' });
});
// --- Inicialização do Servidor ---
app.listen(PORT, () => {
logger.info(Servidor API rodando na porta ${PORT});
logger.info(Acesse: http://localhost:${PORT});
logger.info(Origens CORS permitidas: ${allowedOrigins.join(', ')});
});
Crie um arquivo .env na raiz do projeto para suas variáveis de ambiente:
PORT=3001
CORS_ALLOWED_ORIGINS=http://localhost:8080,http://127.0.0.1:5500,https://seucliente.com,https://outrocliente.io
Comentários Detalhados Linha por Linha
require('dotenv').config();: Carrega as variáveis definidas no arquivo.envparaprocess.env, mantendo segredos e configurações fora do código fonte.- Winston Logger: Configura um logger robusto que registra informações no console e em arquivos (
error.logpara erros,combined.logpara todos os logs). Isso é um padrão enterprise para monitoramento. const app = express();: Inicializa a aplicação Express.const PORT = process.env.PORT || 3000;: Define a porta de execução, preferencialmente via variável de ambiente.- CORS_ALLOWED_ORIGINS: No
.env, definimos uma lista de origens separadas por vírgula. O código converte essa string em um array. Esta é a maneira mais segura e flexível de gerenciar as origens permitidas em produção. corsOptions: Objeto de configuração detalhado para o middlewarecors:origin: Uma função de callback que verifica dinamicamente a origem da requisição. Se a origem estiver na listaallowedOriginsou for uma requisição sem origem (comocURL), ela é permitida. Caso contrário, é bloqueada. Este é o controle mais granular e recomendado.methods: Especifica os métodos HTTP (GET, POST, PUT, DELETE, OPTIONS) que são permitidos para requisições cross-origin.allowedHeaders: Define quais cabeçalhos HTTP personalizados ou não-padrão são permitidos nas requisições cross-origin.Authorizationé vital para APIs que usam tokens JWT, por exemplo.credentials: true: Permite que o navegador inclua cookies, cabeçalhos de autorização HTTP ou certificados TLS em requisições cross-origin. Se você usa autenticação baseada em sessão ou JWT via cookies, isso é essencial. O cliente também deve configurarwithCredentials = true.optionsSuccessStatus: 200: Define o status de sucesso para requisições preflight (OPTIONS).
app.use(cors(corsOptions));: Aplica o middlewarecorscom as opções definidas globalmente para todas as rotas.- CORS Manual (comentado): Incluí um bloco comentado mostrando como você faria a configuração de CORS “na mão”, sem o pacote
cors. É bom para entender os cabeçalhos subjacentes, mas o pacote é preferível para a maioria dos cenários devido à sua simplicidade e robustez. app.use(express.json());: Middleware para parsear o corpo das requisições com JSON.- Rotas de Exemplo: As rotas
/dadosdemonstram uma API RESTful simples, simulando operações de banco de dados. - Validação de Entrada: Um exemplo básico de validação na rota
POST /dados. Em um sistema enterprise, isso seria muito mais robusto, talvez com bibliotecas comoJoiouYup. - Middleware de Erros: Um handler global para capturar e logar erros inesperados, retornando uma mensagem genérica ao cliente.
app.listen(...): Inicia o servidor e registra mensagens informativas no log.
Configurações Específicas para HostGator Plano M
O HostGator Plano M é uma hospedagem compartilhada, predominantemente configurada para PHP. Rodar Node.js diretamente em um ambiente como o “Plano M” tradicional pode ser um desafio, pois ele não oferece suporte nativo e flexível para processos Node.js de longa duração ou gerenciadores de processos como PM2.
No entanto, se você consegue instalar e executar Node.js via SSH (que alguns planos compartilhados da HostGator podem permitir), a configuração de CORS permanece a mesma dentro do seu código Node.js. O que importa é que sua aplicação Express receba as requisições e tenha a chance de processar os cabeçalhos CORS.
Pontos a considerar no HostGator (ou ambiente similar):
- Variáveis de Ambiente: Garanta que as variáveis
CORS_ALLOWED_ORIGINSePORTsejam configuradas no ambiente onde seu Node.js está sendo executado. Geralmente, isso é feito através de arquivos.htaccess(se o Apache for o proxy) ou diretamente no script de inicialização do seu processo Node.js. Por exemplo, em.htaccessvocê poderia adicionar:SetEnv CORS_ALLOWED_ORIGINS "https://seusite.com,https://outro.com". - Proxy Reverso (Apache/Nginx): Em muitos ambientes de hospedagem compartilhada, o Apache ou Nginx atua como um proxy reverso para aplicações Node.js. Nesses casos, o servidor web (Apache/Nginx) também pode ser configurado para adicionar cabeçalhos CORS. Se você tiver problemas com CORS mesmo com a configuração no Express, verifique se há alguma configuração de CORS no nível do servidor web que esteja sobrescrevendo ou interferindo. Em geral, é melhor que sua aplicação Node.js seja a fonte única da verdade para CORS.
- Porta: Em hospedagens compartilhadas, você pode não ter controle sobre a porta. Sua aplicação Node.js pode precisar ouvir em uma porta arbitrária fornecida pelo ambiente (ex: via uma variável de ambiente como
process.env.PORT) e ser acessada via um proxy reverso configurado para a porta 80/443.
Error Handling Otimizado
Nosso logger com Winston possibilita a captura e persistência de erros, o que é crucial em produção. O middleware de erro global (app.use((err, req, res, next) => {...})) garante que qualquer erro não tratado dentro das rotas seja capturado, logado, e uma resposta padronizada seja enviada ao cliente, evitando vazamento de informações sensíveis.
Testes Básicos Incluídos
Para testar o servidor, execute-o:
node server.js
Você pode testar as rotas usando curl (ignora CORS) ou um cliente HTTP como o Postman/Insomnia. O verdadeiro teste de CORS se dá no navegador.
Teste GET (deve funcionar)
📚 Informações da Aula
Curso: API Completo - Node.js & Express
Tempo estimado: 25 minutos
Pré-requisitos: JavaScript básico
curl http://localhost:3001/dados
Teste POST (com Content-Type JSON, simula preflight)
curl -X POST -H "Content-Type: application/json" -d '{"nome":"Teclado Mecanico","preco":450.00}' http://localhost:3001/dados
Para o teste de navegador, crie um arquivo cliente.html em qualquer lugar, por exemplo na área de trabalho, e abra-o com Live Server (extensão do VS Code) ou similar, que irá servi-lo em http://127.0.0.1:5500 ou http://localhost:8080 (dependendo da sua variável CORS_ALLOWED_ORIGINS):
Teste de CORS com API Node.js Cliente para Teste de CORS
Este cliente está rodando em
http://127.0.0.1:5500(ou similar), que deve ser uma origem permitida no seu servidor Node.js.
Resposta da API:
Aguardando requisição...
Exercício Hands-On (5 min)
Para solidificar seu conhecimento, vamos a um desafio prático.
Desafio prático para implementar sozinho
Modifique a API existente para:
- Adicionar uma nova rota
/relatoriosque apenas permita requisiçõesGETe de uma origem específica:https://dashboard.seuexemplo.com. - Garantir que a rota
/dadosaceitePUTpara atualizar um produto existente, mas apenas da origemhttps://editor.seuexemplo.com. - Incluir um cabeçalho customizado
X-Api-Keynas requisiçõesPOSTePUTpara ambas as rotas. - Adicionar um logging detalhado no servidor para cada requisição CORS, informando a origem, o método e se foi permitida ou negada.
Solução detalhada passo a passo
Primeiro, atualize seu arquivo .env com as novas origens permitidas:
PORT=3001
CORS_ALLOWED_ORIGINS=http://localhost:8080,http://127.0.0.1:5500,https://seucliente.com,https://outrocliente.io,https://dashboard.seuexemplo.com,https://editor.seuexemplo.com
Agora, modifique o arquivo server.js:
// ... (imports e configuração do logger permanecem os mesmos) ...
// --- Configuração de CORS (Variantes) ---
const allowedOrigins = process.env.CORS_ALLOWED_ORIGINS
? process.env.CORS_ALLOWED_ORIGINS.split(',')
: ['http://localhost:8080', 'http://127.0.0.1:5500'];
// Função auxiliar para verificar a origem e logar
const checkCorsOrigin = (origin, callback, specificAllowedOrigins = []) => {
const combinedAllowed = [...allowedOrigins, ...specificAllowedOrigins];
if (!origin || combinedAllowed.includes(origin)) {
logger.info(CORS: Requisição da origem '${origin || 'N/A'}' permitida. (Rotas padrão/específicas));
callback(null, true);
} else {
logger.warn(CORS: Requisição da origem '${origin}' NEGADA. (Rotas padrão/específicas));
callback(new Error('Não permitido pelo CORS'), false);
}
};
// Opções CORS globais para a maioria das rotas
const defaultCorsOptions = {
origin: (origin, callback) => checkCorsOrigin(origin, callback),
methods: ['GET', 'POST', 'OPTIONS'], // Limitei para fins de demonstração que PUT virá depois
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'X-Api-Key'],
credentials: true,
optionsSuccessStatus: 200
};
app.use(cors(defaultCorsOptions)); // Aplica opções padrão
// --- Middleware para parsing de JSON no corpo das requisições ---
app.use(express.json());
// --- Rotas da API (Exemplo) ---
// ... (rota raiz e produtos permanecem os mesmos) ...
// Rota para obter todos os produtos
app.get('/dados', (req, res) => {
logger.info('Requisição GET /dados recebida.');
res.status(200).json(produtos);
});
// Rota para adicionar um novo produto
app.post('/dados', (req, res) => {
logger.info(Requisição POST /dados recebida da origem: ${req.headers.origin}. X-Api-Key: ${req.headers['x-api-key'] || 'N/A'});
const { nome, preco } = req.body;
if (!nome || typeof nome !== 'string' || !preco || typeof preco !== 'number') {
logger.error('Validação falhou: dados de produto inválidos.');
return res.status(400).json({ mensagem: 'Dados de produto inválidos. Nome e Preço são obrigatórios.' });
}
const novoProduto = {
id: produtos.length + 1,
nome,
preco
};
produtos.push(novoNovoProduto);
logger.info(Produto adicionado: ${JSON.stringify(novoNovoProduto)});
res.status(201).json(novoNovoProduto);
});
// --- Rota PUT para /dados/:id com CORS específico ---
// Para esta rota, vamos usar um middleware CORS local para sobrescrever as opções globais
const editorCorsOptions = {
origin: (origin, callback) => checkCorsOrigin(origin, callback, ['https://editor.seuexemplo.com']),
methods: ['PUT', 'OPTIONS'], // Apenas PUT e OPTIONS são permitidos
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'Accept', 'X-Api-Key'],
credentials: true,
optionsSuccessStatus: 200
};
app.put('/dados/:id', cors(editorCorsOptions), (req, res) => {
logger.info(Requisição PUT /dados/:id recebida da origem: ${req.headers.origin}. X-Api-Key: ${req.headers['x-api-key'] || 'N/A'});
const { id } = req.params;
const { nome, preco } = req.body;
const produtoIndex = produtos.findIndex(p => p.id === parseInt(id));
if (produtoIndex === -1) {
logger.warn(Produto com ID ${id} não encontrado para atualização.);
return res.status(404).json({ mensagem: 'Produto não encontrado.' });
}
// Validação de entrada
if (!nome || typeof nome !== 'string' || !preco || typeof preco !== 'number') {
logger.error('Validação falhou: dados de produto inválidos para atualização.');
return res.status(400).json({ mensagem: 'Dados de produto inválidos. Nome e Preço são obrigatórios.' });
}
produtos[produtoIndex] = { ...produtos[produtoIndex], nome, preco };
logger.info(Produto com ID ${id} atualizado para: ${JSON.stringify(produtos[produtoIndex])});
res.status(200).json(produtos[produtoIndex]);
});
// --- Nova rota /relatorios com CORS específico ---
const dashboardCorsOptions = {
origin: (origin, callback) => checkCorsOrigin(origin, callback, ['https://dashboard.seuexemplo.com']),
methods: ['GET', 'OPTIONS'], // Apenas GET e OPTIONS são permitidos
allowedHeaders: ['Authorization'], // Apenas Authorization é permitido para relatórios
credentials: true,
optionsSuccessStatus: 200
};
app.get('/relatorios', cors(dashboardCorsOptions), (req, res) => {
logger.info(Requisição GET /relatorios recebida da origem: ${req.headers.origin}.);
// Simula a busca de dados de relatório
const relatorio = {
totalVendas: 150000.00,
clientesAtivos: 1200,
ultimasTransacoes: [
{ id: 'TRX001', valor: 250.00, data: '2023-10-26' },
{ id: 'TRX002', valor: 1500.00, data: '2023-10-25' }
]
};
res.status(200).json(relatorio);
});
// ... (middleware de tratamento de erros global e inicialização do servidor permanecem os mesmos) ...
Como testar e validar o resultado
- Reinicie seu servidor Node.js com
node server.js. - Para
/relatorios:- Tente acessar
http://localhost:3001/relatoriosde um navegador ou docliente.html. Ele deve ser bloqueado, poishttp://localhostouhttp://127.0.0.1:5500não estão na lista de origens permitidas especificamente para esta rota (apenashttps://dashboard.seuexemplo.com). Você verá um erro de CORS no console do navegador. - Para um teste “bem-sucedido” de
/relatorios, você precisaria de um cliente JavaScript rodando emhttps://dashboard.seuexemplo.com. Para simular, você pode adicionar temporariamentehttp://localhost:8080(ou a porta do seu Live Server) à lista de origens paradashboardCorsOptionse tentar novamente.
- Tente acessar
- Para
PUT /dados/:id:- Modifique seu
cliente.htmlpara incluir um botão que faça uma requisiçãoPUTcom um cabeçalhoX-Api-Key. - Tente fazer um
PUTdehttp://localhost:8080(ou a porta do seu Live Server). Ele deve ser bloqueado, a menos que você adicione esta origem à lista deeditorCorsOptions. - Tente com
curl:curl -X PUT -H "Content-Type: application/json" -H "X-Api-Key: meu_segredo" -d '{"nome":"Mouse Ultra Atualizado","preco":250.00}' http://localhost:3001/dados/1(Este
curlirá ignorar a política de CORS, mas você verá o log no servidor com oX-Api-Key).
- Modifique seu
- Verifique os Logs: No seu terminal onde o servidor está rodando, observe os logs do Winston. Você verá mensagens claras sobre qual origem tentou acessar qual rota e se foi permitida ou negada, juntamente com o cabeçalho
X-Api-Key.
Troubleshooting dos erros mais comuns
CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.: O erro mais comum. Significa que a origem do seu cliente não está na lista de origens permitidas no seu servidor, ou o middleware CORS não foi aplicado corretamente na rota acessada. VerifiqueCORS_ALLOWED_ORIGINSno seu.enve as configurações decorsOptions.- Requisições
OPTIONSfalhando: Se você está vendo erros com métodosOPTIONS, significa que o servidor não está respondendo corretamente às requisições preflight. Verifique seapp.use(cors(corsOptions))está antes de suas rotas e se os métodos (incluindoOPTIONS) e cabeçalhos permitidos estão corretos no seucorsOptions. The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '' when the request's credentials mode is 'include'.: Você está usandocredentials: trueno seucorsOptions, mas a origem permitida está definida como*. Para permitir credenciais, você deve especificar origens explícitas ou usar uma função que valida dinamicamente, como fizemos.- Cabeçalhos personalizados bloqueados: Se um cabeçalho como
AuthorizationouX-Api-Keynão está sendo enviado, verifique se ele está incluído na listaallowedHeadersem seucorsOptions.
Próximos passos sugeridos
Continue explorando!
- Pesquise sobre como configurar CORS em servidores proxy como Nginx ou Apache, caso sua infraestrutura use um.
- Aprenda sobre segurança de APIs, incluindo autenticação (JWT, OAuth2) e autorização, que frequentemente dependem de CORS para funcionar corretamente em cenários cross-origin.
- Implemente um ambiente de desenvolvimento e produção para suas variáveis de ambiente (ex:
.env.development,.env.production) para gerenciar as origens permitidas de forma mais granular. - Considere adicionar um gerenciador de configurações mais robusto, como
configounconf, para cenários enterprise complexos.
🚀 Pronto para a próxima aula?
Continue sua jornada no desenvolvimento de APIs e domine Node.js & Express!