Erros de CORS no API Gateway: Como Configurar e o Que Seu Lambda Precisa Retornar
Você abre o console do navegador e vê aquele erro clássico: 'Access to fetch at ... has been blocked by CORS policy'. O backend responde 200 no Postman, mas o frontend quebra. Esse é um dos erros mais comuns ao integrar um frontend com API Gateway — e a causa quase sempre está em dois lugares ao mesmo tempo: a configuração do API Gateway E os headers que o Lambda retorna.
TL;DR — Resumo Rápido
| Camada | O que precisa estar correto |
|---|---|
| API Gateway (REST) | Habilitar CORS no recurso, criar método OPTIONS com resposta 200, configurar headers de resposta no método |
| API Gateway (HTTP) | Configurar CORS diretamente nas configurações da API |
| Lambda (ambos) | Retornar Access-Control-Allow-Origin e outros headers CORS em TODA resposta, incluindo erros |
| Erro mais comum | Configurar o API Gateway mas esquecer os headers no Lambda — o preflight passa, a requisição real falha |
Como o CORS Funciona no Contexto do API Gateway
Antes de sair clicando em 'Enable CORS' no console, vale entender o que está acontecendo. O navegador, ao detectar uma requisição cross-origin, executa um preflight — uma requisição HTTP do tipo OPTIONS enviada antes da requisição real. Essa requisição OPTIONS pergunta ao servidor: 'você aceita requisições desse origin com esses métodos e headers?'
O servidor precisa responder com headers específicos autorizando a operação. Se a resposta do OPTIONS não contiver esses headers, o navegador bloqueia a requisição real antes mesmo de ela sair. Mas aqui está o ponto que engana a maioria: mesmo que o preflight passe, a requisição real também precisa retornar os headers CORS. O navegador verifica novamente.
(Preflight) AG-->>B: 200 OK
Access-Control-Allow-* Note over B: Preflight aprovado B->>AG: GET /usuarios AG->>L: Invoca Lambda L-->>AG: 200 + headers CORS AG-->>B: 200 + headers CORS Note over B: Navegador valida headers
e libera a resposta
- Preflight (OPTIONS): O navegador envia uma requisição OPTIONS antes da chamada real para verificar permissões CORS.
- Resposta do API Gateway ao OPTIONS: O API Gateway responde com os headers
Access-Control-Allow-*configurados. Se ausentes, o navegador bloqueia tudo. - Requisição real (GET/POST/etc): O navegador só envia a requisição real se o preflight foi aprovado.
- Lambda processa e responde: O Lambda precisa incluir os headers CORS na resposta — o API Gateway não os injeta automaticamente no modo de integração Lambda Proxy.
- Navegador valida: Se os headers CORS estiverem ausentes na resposta real, o navegador bloqueia a resposta mesmo com status 200.
Diferença Entre API Gateway REST API e HTTP API
O console tem dois tipos de API Gateway com comportamentos distintos para CORS. Confundir os dois é garantia de horas perdidas.
no recurso"] D --> E["Configurar headers
Access-Control-Allow-*"] E --> F["Deploy obrigatório
no Stage"] C --> G["Configurar CORS
nas Settings da API"] F --> H["Lambda retorna
headers CORS"] G --> H H --> I["CORS funcionando"]
- REST API: Configuração manual — você precisa criar o método OPTIONS, configurar as respostas de integração e os headers individualmente. O botão 'Enable CORS' no console automatiza parte disso, mas tem limitações.
- HTTP API: Configuração nativa de CORS nas configurações da API. Mais simples, mas o Lambda ainda precisa retornar os headers nas respostas reais quando se usa integração Lambda Proxy.
Configurando CORS no API Gateway REST API (Console)
O botão 'Enable CORS' no console da REST API faz o seguinte: cria um método OPTIONS no recurso selecionado, configura uma resposta mock com status 200 e adiciona os headers Access-Control-Allow-Headers, Access-Control-Allow-Methods e Access-Control-Allow-Origin à resposta do método. Depois disso, você precisa fazer o deploy da API para que as mudanças entrem em vigor.
Passo a passo via console:
- Acesse o API Gateway no console AWS.
- Selecione sua REST API.
- No painel de recursos, selecione o recurso desejado (ex:
/usuarios). - Clique em Actions → Enable CORS.
- Configure os campos:
- Access-Control-Allow-Headers:Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token
- Access-Control-Allow-Methods: os métodos que seu recurso aceita (ex:GET,POST,OPTIONS)
- Access-Control-Allow-Origin: o origin do seu frontend (ex:https://meusite.com) ou*para desenvolvimento - Clique em Enable CORS and replace existing CORS headers.
- Faça o deploy da API — sem isso, nada muda. Vá em Actions → Deploy API, selecione o stage e confirme.
Via CLI, você pode verificar se o método OPTIONS existe e está configurado:
aws apigateway get-method \
--rest-api-id SEU_API_ID \
--resource-id SEU_RESOURCE_ID \
--http-method OPTIONS \
--region us-east-1
Para listar seus recursos e obter os IDs necessários:
aws apigateway get-resources \
--rest-api-id SEU_API_ID \
--region us-east-1
Configurando CORS no API Gateway HTTP API (Console)
A HTTP API tem uma seção dedicada de CORS nas configurações. É mais direta e não exige criação manual de método OPTIONS.
- Acesse sua HTTP API no console.
- No menu lateral, clique em CORS.
- Clique em Configure e preencha:
- Access-Control-Allow-Origin: o origin do frontend
- Access-Control-Allow-Headers: headers que o cliente enviará
- Access-Control-Allow-Methods: métodos permitidos
- Access-Control-Max-Age: tempo em segundos para cache do preflight - Salve as configurações.
Via CLI para verificar a configuração CORS de uma HTTP API:
aws apigatewayv2 get-api \
--api-id SEU_API_ID \
--region us-east-1 \
--query 'CorsConfiguration'
O Que Seu Lambda Precisa Retornar — Headers Obrigatórios
Aqui está onde a maioria erra. Quando você usa integração Lambda Proxy (que é o padrão em quase todos os tutoriais), o API Gateway repassa a resposta do Lambda diretamente para o cliente — sem modificar os headers. Isso significa que o Lambda é responsável por incluir os headers CORS em cada resposta.
Pense assim: o API Gateway configura o que responder ao preflight OPTIONS. Mas nas requisições reais, ele só faz o papel de proxy — o que o Lambda retornar é o que o cliente recebe. Se o Lambda não incluir os headers CORS, o navegador rejeita a resposta mesmo com status 200.
Estrutura mínima de resposta do Lambda com headers CORS:
🔽 Clique para expandir — Exemplo de resposta Lambda (Python)
import json
def lambda_handler(event, context):
return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Origin': 'https://meusite.com',
'Access-Control-Allow-Headers': 'Content-Type,Authorization',
'Access-Control-Allow-Methods': 'GET,POST,OPTIONS',
'Content-Type': 'application/json'
},
'body': json.dumps({'mensagem': 'sucesso'})
}
🔽 Clique para expandir — Exemplo de resposta Lambda (Node.js)
exports.handler = async (event) => {
return {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': 'https://meusite.com',
'Access-Control-Allow-Headers': 'Content-Type,Authorization',
'Access-Control-Allow-Methods': 'GET,POST,OPTIONS',
'Content-Type': 'application/json'
},
body: JSON.stringify({ mensagem: 'sucesso' })
};
};
Um detalhe crítico: inclua os headers CORS também nos blocos de tratamento de erro. Se o Lambda lançar uma exceção e retornar status 500 sem os headers CORS, o navegador vai bloquear a resposta de erro — e você não vai ver a mensagem de erro no frontend, só o erro de CORS.
Diagnóstico: Sintoma → Diagnóstico Errado → Causa Real → Correção
O cenário clássico: você habilita o CORS no console, faz o deploy, testa no Postman — funciona. Abre o frontend — erro de CORS. A conclusão imediata é que o API Gateway não está configurado corretamente. Você passa horas revisando o método OPTIONS, os headers de resposta, o stage de deploy.
A causa real: o Postman não envia preflight. Ele não é um navegador. Quando o Postman chama GET /usuarios, ele não verifica headers CORS — simplesmente recebe a resposta. O navegador, por outro lado, verifica os headers CORS na resposta real do GET /usuarios. Como o Lambda não estava retornando Access-Control-Allow-Origin na resposta, o navegador bloqueava.
O API Gateway estava correto. O Lambda é que não tinha os headers. A correção foi adicionar os headers na resposta do Lambda — não mexer mais no API Gateway.
Para confirmar qual camada está falhando, use o curl simulando um preflight:
curl -v -X OPTIONS https://SEU_API_ID.execute-api.us-east-1.amazonaws.com/prod/usuarios \
-H 'Origin: https://meusite.com' \
-H 'Access-Control-Request-Method: GET' \
-H 'Access-Control-Request-Headers: Content-Type'
E depois simule a requisição real:
curl -v -X GET https://SEU_API_ID.execute-api.us-east-1.amazonaws.com/prod/usuarios \
-H 'Origin: https://meusite.com' \
-H 'Content-Type: application/json'
Se o OPTIONS retorna os headers mas o GET não retorna Access-Control-Allow-Origin, o problema está no Lambda — não no API Gateway.
Permissões IAM Necessárias
Para executar os comandos CLI de diagnóstico e configuração, a role ou usuário precisa das seguintes permissões mínimas:
🔽 Clique para expandir — Política IAM mínima para diagnóstico CORS
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"apigateway:GET"
],
"Resource": [
"arn:aws:apigateway:us-east-1::/restapis/*",
"arn:aws:apigateway:us-east-1::/apis/*"
]
}
]
}
Para modificar configurações de CORS via CLI ou console, adicione apigateway:PUT e apigateway:PATCH ao escopo acima. Siga o princípio de menor privilégio — em produção, restrinja ao ARN específico da API.
Checklist de Verificação CORS no API Gateway
- REST API: O método OPTIONS existe no recurso? A resposta do método tem os três headers
Access-Control-Allow-*? O deploy foi feito após as mudanças? - HTTP API: A configuração CORS está salva nas configurações da API? O origin está correto (sem barra no final)?
- Lambda: Todos os handlers de resposta — incluindo erros — retornam
Access-Control-Allow-Origin? - Origin: O valor de
Access-Control-Allow-Origincorresponde exatamente ao origin do frontend?https://meusite.comehttps://meusite.com/são diferentes para alguns navegadores. - Credenciais: Se o frontend envia cookies ou headers de autenticação,
Access-Control-Allow-Credentials: trueé necessário — e nesse casoAccess-Control-Allow-Originnão pode ser*.
Próximos Passos e Recursos Oficiais
Com CORS configurado corretamente nos dois lados — API Gateway e Lambda — o erro de bloqueio cross-origin desaparece. O ponto de atenção contínuo é garantir que qualquer novo endpoint ou novo handler de erro no Lambda também inclua os headers. Uma abordagem comum em produção é centralizar a construção da resposta em uma função utilitária que sempre injeta os headers CORS, evitando que um novo desenvolvedor esqueça de incluí-los.
- Documentação oficial: Enabling CORS for a REST API (AWS)
- Documentação oficial: Configuring CORS for an HTTP API (AWS)
Glossário de Termos-Chave
| Termo | Definição |
|---|---|
| CORS (Cross-Origin Resource Sharing) | Mecanismo do navegador que controla quais origens podem acessar recursos de um domínio diferente via requisições HTTP. |
| Preflight Request | Requisição OPTIONS enviada automaticamente pelo navegador antes de requisições cross-origin para verificar permissões do servidor. |
| Lambda Proxy Integration | Modo de integração onde o API Gateway repassa o evento completo ao Lambda e retorna a resposta do Lambda diretamente ao cliente, sem modificações. |
| Access-Control-Allow-Origin | Header HTTP que especifica quais origens têm permissão para acessar o recurso. Obrigatório em toda resposta CORS. |
| Stage (API Gateway) | Ambiente de deploy de uma API REST (ex: prod, dev). Mudanças na configuração só têm efeito após um novo deploy no stage. |
Comentários
Postar um comentário