Pular para o conteúdo

Programando Soluções

Como tratar erro 404 de rota ou página não existente no Express

erro 404

Introdução

O erro 404 é utilizado quando uma rota, página do sistema não é encontrado. Esse tipo de erro é comum acontecer quando o usuário solicita uma rota da API que não existe, ou tenta entrar em uma página que não existe mais.

O Express tem uma forma de tratar esse erro para informar ao usuário de maneira mais amigável que ele aconteceu, seja via API, caso seu backend seja uma API rest, ou criando uma página para isso.

Como o Express lida com erro 404

Ele não tem uma forma explícita de fazer essa verificação, porém ele disponibiliza uma forma interessante para realizar o tratamento de erro 404.

Quando uma requisição chega, ele tenta encontrar a rota solicitada com base em todas as rotas existentes no sistema, e quando não encontra nenhuma ele retorna o erro.

Porém, antes dele executar o retorno, é possível adicionar uma função, que vai indicar que se o Express não entrou em nenhuma rota, ele deve entrar nessa para realizar o retorno personalizado do erro 404.

Preparei uma imagem para ilustrar esse fluxo:

erro 404 1

Neste exemplo, é um sistema que contém três rotas, o express recebe a solicitação e tenta encontrar a rota desejada entre essas três, caso ele não encontre, ele executa o que está na “rota de erro 404”.

Implementando a solução

Para implementar, é necessário ter um sistema básico com o Node e com o Express instalado. Caso queira, veja aqui como fazer isso.

Como o exemplo na imagem, vou criar três rotas no sistema, o arquivo principal, que no meu caso é o server.js, ficará dessa maneira:

const express = require("express");
const app = express();

app.get('/', (req, res) => {
    res.json('Ola mundo 1');
})

app.get('/rota2', (req, res) => {
    res.json('Ola mundo 2');
})

app.get('/rota3', (req, res) => {
    res.json('Ola mundo 3');
})

app.listen(3000, () => {
  console.log("Funcionando");
});

Com o código desse jeito, caso seja solicitado uma rota que não existe, terá o seguinte retorno:

erro 404 2

E não é isso que queremos, queremos melhorar esse retorno, para exibir da melhor forma para o usuário, informando o erro 404 de que a rota não existe.

No server.js, vamos adicionar um middleware após todas as rotas, que será executado quando não existir a rota solicitada, ele precisa estar após todas as rotas, esse é o middleware:

app.use(function(req, res, next) {
    res.status(404).send("Esta rota não existe");
});

E agora, se testar o retorno, terá a mensagem de erro personalizada:

erro 404 3

Retornando um JSON

Talvez o seu sistema seja uma API Rest, então nesse caso, convém retornar um JSON para o erro 404 com a resposta de que a rota não existe.

Para isso, é preciso alterar o retorno de send para json, e colocar o JSON desejado para retornar ao usuário, a função fica dessa forma:

app.use(function(req, res, next) {
    res.status(404).json({message: 'Erro ao acessar a rota'});
});

E o resultado é:

erro 404 4

Caso você acesse pelo postman ou insomnia o retorno será o mesmo com o erro 404, inclusive com o status.

Mostrando uma página de erro 404

Caso não seja uma API Rest, você pode renderizar uma página personalizada com o erro 404, esse recurso é comum nos sistemas web e muito interessante, veja como implementar.

Será necessário instalar uma biblioteca que é o ejs, ela indica que o sistema utilizará o engine de views sendo o ejs, que basicamente você pode renderizar um HTML, mas também pode adicionar variáveis no código, criando uma página dinâmica.

Para instalar o ejs, utilize este comando no terminal:

npm install ejs

Depois disso, volte no código, e indique ao Node que utilizará esse engine de views, coloque o seguinte código abaixo da constante app:

app.set('view engine', 'ejs');

Agora crie um diretório chamado views, e dentro dele um arquivo chamado 404.ejs:

erro 404 5

O conteúdo desse arquivo 404.ejs será esse:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Erro 404</title>
</head>
<body>
  <h1>404</h1>
  <p>A seguinte rota não foi encontrada: <%= url %></p>
</body>
</html>

Agora volte no middleware, e atualize a função, para em vez de retornar um json, renderizar uma página, que será a 404, dessa forma:

app.use(function(req, res, next) {
    res.render('404', { url: req.url })
});

Repare que no HTML, no parágrafo, está sendo renderizado a variável url, para renderizar uma variável qualquer no ejs, essa é a sintaxe <%= nome_variavel %>.

E como está sendo renderizado uma variável, precisamos passar ela para a view, e para enviar ela é necessário passar no res.render, depois de colocar o nome do arquivo, é possível passar um json com todas as variáveis que serão utilizadas.

Nesse caso, parramos somente a variável url, e o valor que será passado, é a url requisitada pelo usuário, a url que não foi encontrada.

O arquivo server.js deve ficar dessa forma:

const express = require("express");
const app = express();

app.set('view engine', 'ejs');

app.get('/', (req, res) => {
    res.json('Ola mundo 1');
})

app.get('/rota2', (req, res) => {
    res.json('Ola mundo 2');
})

app.get('/rota3', (req, res) => {
    res.json('Ola mundo 3');
})

app.use(function(req, res, next) {
    res.render('404', { url: req.url })
});

app.listen(3000, () => {
  console.log("Funcionando");
});

E quando o usuário acessar uma rota não existente, o resultado será esse:

erro 404 6

Se o usuário acessar outra rota que não seja a /teste, o sistema informará dinamicamente:

erro 404 7

No caso, essa página contém um HTML simples, e caso queira, você pode implementar um HTML mais personalizado e amigável para o usuário.

E como exemplo para isso, troquei o HTML dessa página 404.ejs, e coloquei um com uma interface mais bonita e amigável para o usuário:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Erro 404 - Página não encontrada</title>
<style>
body {
  background-color: #2F3242;
}
svg {
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -250px;
  margin-left: -400px;
}
.message-box {
  height: 200px;
  width: 380px;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -100px;
  margin-left: 50px;
  color: #FFF;
  font-family: Roboto;
  font-weight: 300;
}
.message-box h1 {
  font-size: 60px;
  line-height: 46px;
  margin-bottom: 40px;
}
.buttons-con .action-link-wrap {
  margin-top: 40px;
}
.buttons-con .action-link-wrap a {
  background: #68c950;
  padding: 8px 25px;
  border-radius: 4px;
  color: #FFF;
  font-weight: bold;
  font-size: 14px;
  transition: all 0.3s linear;
  cursor: pointer;
  text-decoration: none;
  margin-right: 10px
}
.buttons-con .action-link-wrap a:hover {
  background: #5A5C6C;
  color: #fff;
}

#Polygon-1 , #Polygon-2 , #Polygon-3 , #Polygon-4 , #Polygon-4, #Polygon-5 {
  animation: float 1s infinite ease-in-out alternate;
}
#Polygon-2 {
  animation-delay: .2s; 
}
#Polygon-3 {
  animation-delay: .4s; 
}
#Polygon-4 {
  animation-delay: .6s; 
}
#Polygon-5 {
  animation-delay: .8s; 
}

@keyframes float {
	100% {
    transform: translateY(20px);
  }
}
@media (max-width: 450px) {
  svg {
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -250px;
    margin-left: -190px;
  }
  .message-box {
    top: 50%;
    left: 50%;
    margin-top: -100px;
    margin-left: -190px;
    text-align: center;
  }
}
</style>
</head>

<body>
    
<svg width="380px" height="500px" viewBox="0 0 837 1045" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
        <path d="M353,9 L626.664028,170 L626.664028,487 L353,642 L79.3359724,487 L79.3359724,170 L353,9 Z" id="Polygon-1" stroke="#007FB2" stroke-width="6" sketch:type="MSShapeGroup"></path>
        <path d="M78.5,529 L147,569.186414 L147,648.311216 L78.5,687 L10,648.311216 L10,569.186414 L78.5,529 Z" id="Polygon-2" stroke="#EF4A5B" stroke-width="6" sketch:type="MSShapeGroup"></path>
        <path d="M773,186 L827,217.538705 L827,279.636651 L773,310 L719,279.636651 L719,217.538705 L773,186 Z" id="Polygon-3" stroke="#795D9C" stroke-width="6" sketch:type="MSShapeGroup"></path>
        <path d="M639,529 L773,607.846761 L773,763.091627 L639,839 L505,763.091627 L505,607.846761 L639,529 Z" id="Polygon-4" stroke="#F2773F" stroke-width="6" sketch:type="MSShapeGroup"></path>
        <path d="M281,801 L383,861.025276 L383,979.21169 L281,1037 L179,979.21169 L179,861.025276 L281,801 Z" id="Polygon-5" stroke="#36B455" stroke-width="6" sketch:type="MSShapeGroup"></path>
    </g>
</svg>
<div class="message-box">
  <h1>404</h1>
  <p>A seguinte página não foi encontrada: <%= url %></p>
  <div class="buttons-con">
    <div class="action-link-wrap">
      <a href="http://localhost:3000" class="link-button">Voltar para o início</a>
    </div>
  </div>
</div>
</body>
</html>

Agora quando o usuário acessar uma página que não existe, o resultado será esse:

erro 404 8

Essa tela eu não desenvolvi ela, eu peguei no site Free Front End que já tem uma série de páginas 404, você pode dar uma olhada e procurar uma que se encaixa melhor no seu sistema.

Vídeo sobre o assunto

Gravei um vídeo explicando todos os itens desse artigo:

https://youtu.be/icNqDrk9Ojo

Código fonte

Todo o código fonte dos exemplos mostrados estão no meu CodeSandbox

Para ver outros canais onde o posto conteúdo, meu Github e também cursos, veja os Links do Programando Soluções.

Referências

Express

https://freefrontend.com/html-css-404-page-templates/

Este conteúdo te ajudou de alguma forma?

Marcações:
Usamos cookies para lhe proporcionar a melhor experiência possível no nosso site. Ao continuar a usar este site, você concorda com o uso de cookies.
Ok