Como corrigir o erro 404 no Angular ao efetuar o refresh ou acessar rotas diretamente do navegador
O erro 404 no Angular surge quando o servidor web não está configurado para lidar com o roteamento client-side do Angular. Aprenda a corrigir esse problema no Nginx e Apache
Se você trabalha com projetos que usam o framework Angular, talvez tenha enfrentado um problema comum: tudo funciona perfeitamente durante o desenvolvimento. No entanto, após implantar o projeto em produção, ao navegar entre as rotas, você percebe que, ao atualizar a página ou tentar acessar uma rota diretamente na barra de endereços, surge o erro 404 Not Found. Neste texto, vamos entender por que isso acontece e como resolver esse problema.
Servindo arquivos estáticos para web
Arquivos estáticos, como HTML, CSS, JavaScript e imagens, são a base de muitos sites e aplicações web, incluindo projetos Angular. Servi-los de forma eficiente é crucial para garantir uma experiência rápida, confiável e segura para os usuários.
Nesse contexto, softwares como Nginx, Apache e serviços de hospedagem estática como GitHub Pages se destacam por sua simplicidade, performance e escalabilidade. Ao invés de processar cada requisição dinamicamente, esses servidores entregam os arquivos estáticos diretamente aos usuários, reduzindo a carga do servidor e otimizando o tempo de resposta.
Para projetos Angular, essa abordagem é particularmente vantajosa, pois após compilarmos o projeto, o resultado é composto por arquivos estáticos (html, js, css e imagens).
Dito isso, vamos criar um cenário de estudo envolvendo um projeto Angular com algumas rotas. Em seguida, vamos servir os arquivos através do Nginx e Apache para explorar a causa do erro 404 Not Found. Por fim, faremos um ajuste para resolver esse problema.
Cenário de estudo: criando o projeto Angular
Parar criar o projeto Angular:
# Conferindo a versão do Angular/CLI
> ng version
Angular CLI: 18.1.1
Node: 20.12.0
Package Manager: npm 10.8.1
OS: darwin arm64
# Criando o projeto
> ng new \
--skip-git \
--skip-tests \
--standalone \
--strict \
--minimal \
--inline-template \
--routing \
exemplo404
ng new help
para visualizar os parâmetros do comando ng new
Adicionando rotas ao projeto
Com o projeto criado, vamos adicionar 2 componentes, um para cada rota:
# Criando os componentes:
#
# Certifique-se de estar no diretório do projeto.
# Use o comando pwd para verificar seu diretório atual.
#
> ng g c rota1 --skip-tests --style none
> ng g c rota2 --skip-tests --style none
Mapeando as rotas:
Efetuando um teste em modo de desenvolvimento
Com o projeto configurado, vamos testá-lo em modo de desenvolvimento executando o comando npm run start
:
Veja no GIF acima que podemos mudar a rota diretamente na barra de endereços do navegador e atualizar a página sem problemas. Tudo funciona perfeitamente no modo de desenvolvimento.
Compilando o projeto
Visto que o projeto está funcionando corretamente, vamos efetuar o build do projeto com o comando npm run build
. Após o processamento, o resultado do build estará no diretório /dist/exemplo404/browser deste exemplo.
Testando o projeto sendo servido pelo Nginx
Para simular o erro 404, vamos servir os arquivos gerados anteriormente usando o Nginx.
Para evitar a instalação do Nginx no meu computador, usei um container Docker. Utilizei o comando abaixo para criar um container Docker a partir de uma imagem do Nginx:
> docker run \
--name nginx-angular \
-v /<dir do projeto>/dist/exemplo404/browser:/usr/share/nginx/html:ro \
-p 8080:80 \
-d nginx
Explicação do comando:
- --name
Nome do container - -v
Vincula um diretório do meu computador (host) com um diretório dentro do container. - -p:
Vincula uma porta no meu computador (host) com uma porta do container. - -d:
Nome da imagem
Erro 404 Not Found
Após executar o comando acima, o container do Nginx estará em execução, então podemos abrir o navegador e acessar o endereço http://localhost:8080
para carregar a aplicação Angular.
Nexte contexto, se acessarmos localhost:8080/favicon.ico
ou localhost:8080/main-XZS6USHQ.js
, o Nginx retornará o conteúdo desses arquivos corretamente. No entanto, se tentarmos acessar localhost:8080/rota2
, o Nginx devolverá o erro 404 Not Found. Isso ocorre porque o Nginx não sabe como lidar com essa rota. Ele tenta encontrar um arquivo ou diretório chamado rota2
e, como não existe, retorna o erro 404.
Observação: Lembre-se de que configuramos o Nginx para usar o diretório com os arquivos do projeto de exemplo (veja a imagem abaixo). Esses são os arquivos estáticos que o Nginx pode servir:
Por outro lado, se você acessar localhost:8080
ou localhost:8080/index.html
, o Nginx retornará o conteúdo do arquivo index.html
, que é o ponto de entrada da aplicação Angular. Uma vez que a aplicação Angular é carregada e interpretada pelo navegador, ela gerencia as rotas internamente. Isso significa que você pode navegar entre as rotas usando links ou botões dentro da própria aplicação.
Veja no GIF abaixo que a navegação pelos botões funciona perfeitamente. Porém, se usarmos a barra de endereços do navegador ou atualizarmos a página em uma rota diferente da raiz, aparece o erro 404.
Resolvendo o erro 404 Not Found no Nginx
Para resolver isso, é necessário configurar o Nginx para sempre servir o arquivo index.html
para qualquer rota desconhecida. Desta forma, quando o navegador carregar o index.html
, o contexto do Angular será criado, permitindo que o Angular gerencie as rotas após o carregamento inicial.
No caso do Nginx, existe um arquivo de configuração chamado nginx.conf
onde podemos configurar esse comportamento. Para obter o conteúdo desse arquivo podemos executar os seguintes comandos:
# Acessando o terminal do container
> docker exec -it nginx-angular /bin/bash
# Obtendo o conteúdo do arquivo:
> cat /etc/nginx/nginx.conf
Com o conteúdo do arquivo nginx.conf
em mãos, criei um arquivo com o mesmo nome dentro do diretório do projeto Angular (o local é opcional) e fiz a seguinte modificação:
Finalmente removi o container que está em execução e recriei incluindo a configuração do Nginx customizada logo acima:
# Interrompendo a execução do container
> docker container stop nginx-angular
# Removendo o container
> docker container rm nginx-angular
# Criando um novo container
> docker run \
--name nginx-angular \
-v /<dir do projeto>/dist/exemplo404/browser:/usr/share/nginx/html:ro \
-v /<dir do projeto>/nginx.conf:/etc/nginx/nginx.conf:ro \
-p 8080:80 \
-d nginx
Resultado:
Testando o projeto sendo servido pelo Apache
De forma similar ao Nginx, mas agora com o Apache, segui as seguintes etapas:
Criando o container Docker do Apache
Primeiramente criei um container com a imagem do Apache com o comando abaixo:
docker run \
--name apache-angular \
-p 9090:80 \
-v /<dir do projeto>/dist/exemplo404/browser:/usr/local/apache2/htdocs:ro \
-d httpd:2.4
Obtendo o arquivo httpd.conf
Assim como no Nginx, neste momento o container em execução apresenta o mesmo problema do 404. Então de forma similar ao Nginx, precisamos obter o conteúdo do arquivo de configuração do Apache para aplicar uma modificação. Para isto acessei o terminal do container com os seguintes comandos:
> docker exec -it "apache-angular" /bin/bash
# A partir daqui estamos no console
# do container
#
# Obtendo o conteúdo do arquivo httpd.conf:
#
> cat /usr/local/apache2/conf/httpd.conf
Modificando o arquivo de configuração httpd.conf
Então criei um arquivo chamado httpd.conf
no diretório do meu projeto com as seguintes modificações:
Recriando o container
Para finalizar executei os comandos abaixo:
# Para a execução do container
> docker container stop "apache-angular"
# Remove o container
> docker container rm "apache-angular"
# Cria o container
> docker run \
--name apache-angular \
-p 9090:80 \
-v /<dir do projeto>/dist/exemplo404/browser:/usr/local/apache2/htdocs:ro \
-v /<dir do projeto>/httpd.conf:/usr/local/apache2/conf/httpd.conf:ro \
-d httpd:2.4
Resultado:
Considerações
Neste texto, falamos sobre o erro 404 que surge ao atualizar ou acessar rotas client-side diretamente no navegador em aplicações Angular. Abordamos as soluções envolvendo o Nginx e Apache, configurando para entregar o arquivo principal da aplicação (index.html
) quando uma rota não for encontrada.
Outros frameworks ou bibliotecas como React, seguem o mesmo princípio do Angular no roteamento client-side. Então ao configurar o servidor de arquivos estáticos para entregar o index.html
quando uma rota não for encontrada, a aplicação poderá assumir o controle do roteamento e exibir o conteúdo correto.