Como redirecionar erros 404 para uma página no ExpressJS?

203

Não conheço uma função para fazer isso, alguém sabe de uma?

hexacianida
fonte

Respostas:

274

Achei este exemplo bastante útil:

https://github.com/visionmedia/express/blob/master/examples/error-pages/index.js

Portanto, é realmente esta parte:

// "app.router" positions our routes
// above the middleware defined below,
// this means that Express will attempt
// to match & call routes _before_ continuing
// on, at which point we assume it's a 404 because
// no route has handled the request.

app.use(app.router);

// Since this is the last non-error-handling
// middleware use()d, we assume 404, as nothing else
// responded.

// $ curl http://localhost:3000/notfound
// $ curl http://localhost:3000/notfound -H "Accept: application/json"
// $ curl http://localhost:3000/notfound -H "Accept: text/plain"

app.use(function(req, res, next){
  res.status(404);

  // respond with html page
  if (req.accepts('html')) {
    res.render('404', { url: req.url });
    return;
  }

  // respond with json
  if (req.accepts('json')) {
    res.send({ error: 'Not found' });
    return;
  }

  // default to plain-text. send()
  res.type('txt').send('Not found');
});
Felix
fonte
Por favor, defina "manipulado"? O que exatamente marca a rota como tratada?
Timo Huovinen
1
Supus que nenhuma rota correspondente fosse encontrada até esse ponto.
Felix #
2
Para sua informação, o uso de app.routeragora está obsoleto. Veja github.com/strongloop/express/wiki/…
iX3
2
Para a resposta JSON, pode ser melhor usar em res.jsonvez de res.send(). Eles se comportariam da mesma forma no seu código, mas usar res.jsonfará alguma mágica na conversão automática de objetos em cadeias de caracteres onde .send()não. Melhor prevenir do que remediar. expressjs.com/api.html#res.json
wgp
9
Agora esta pergunta aparece no FAQ expressjs.com/starter/faq.html#how-do-you-handle-404s-
Ivan Fraixedes
157

Eu acho que você deve primeiro definir todas as suas rotas e, como a última rota adiciona

//The 404 Route (ALWAYS Keep this as the last route)
app.get('*', function(req, res){
  res.status(404).send('what???');
});

Um aplicativo de exemplo que funciona:

app.js:

var express = require('express'),
    app = express.createServer();

app.use(express.static(__dirname + '/public'));

app.get('/', function(req, res){
  res.send('hello world');
});

//The 404 Route (ALWAYS Keep this as the last route)
app.get('*', function(req, res){
  res.send('what???', 404);
});

app.listen(3000, '127.0.0.1');

alfred@alfred-laptop:~/node/stackoverflow/6528876$ mkdir public
alfred@alfred-laptop:~/node/stackoverflow/6528876$ find .
alfred@alfred-laptop:~/node/stackoverflow/6528876$ echo "I don't find a function for that... Anyone knows?" > public/README.txt
alfred@alfred-laptop:~/node/stackoverflow/6528876$ cat public/README.txt 

.
./app.js
./public
./public/README.txt

alfred@alfred-laptop:~/node/stackoverflow/6528876$ curl http://localhost:3000/
hello world
alfred@alfred-laptop:~/node/stackoverflow/6528876$ curl http://localhost:3000/README.txt
I don't find a function for that... Anyone knows?
Alfred
fonte
6
Bem ... o problema é que o "*" já corresponde aos arquivos .js e .css, e não estão especificados no aplicativo ... bem, não sei se há alguma maneira de capturar exatamente o mesma coisa que o erro 404 ou uma maneira de substituir a mensagem "Não é possível obter ...". De qualquer forma, obrigado
1
Você está usando middleware estático, porque ainda pode servir arquivos estáticos?
Alfred
4
app.get('/public/*', function(req, res){ res.sendfile(__dirname + '/public/' + req.url); })você pode usar esta rota para enviar arquivos estáticos. funciona bem com a rota "*" acima. app.use(express.static(__dirname + '/public'));não funciona para mim, com fio.
22411 Chris
25
Isso não estava funcionando para mim, mas então descobri que o meu app.use(express.static(...))veio atrás app.use(app.router). Depois que os troquei, tudo saiu bem.
Stephen
5
+1 para adicionar o comentário de @ Stephen à sua resposta. Isto não funcionou para mim também até que eu ponha app.use (app.router) APÓS app.use (express.static (...))
braitsch
37

Você pode colocar um middleware na última posição que gera um NotFounderro
ou até renderizar a página 404 diretamente:

app.use(function(req,res){
    res.status(404).render('404.jade');
});
Ganesh Kumar
fonte
9
Por favor, considere um pouco mais detalhado responder da próxima vez ... Os exemplos são geralmente muito bem - e este é um exemplo bom - mas alguma explicação pode ser muito, muito bom, bem ...
Tonny Madsen
2
+1 muito bom! Eu acho que isso é melhor do que uma última rota, porque dessa forma você não precisa da use()sua app.routerna última vez. (como no meu caso)
Alba Mendez
Além disso, isso substitui o comportamento padrão em qualquer solicitação (não apenas GETs). Tente POSTuma URL aleatória com o outro método; retornará o padrão Cannot POST.... Um invasor saberá que você está usando o Express.JS.
Alba Mendez
Muito bom, exceto usando o ejs, basta colocarres.render('404')
locrizak
Provavelmente, isso também deve ter o status (404) res.status (404) .render ('404') #
9781 MartinWebb 2/17/17
32

As respostas acima são boas, mas na metade delas você não receberá 404 quando o código de status HTTP retornou e na outra metade, não será possível renderizar um modelo personalizado. A melhor maneira de ter uma página de erro personalizada (404) no Expressjs é

app.use(function(req, res, next){
    res.status(404).render('404_error_template', {title: "Sorry, page not found"});
});

Coloque esse código no final de todos os seus mapeamentos de URL.

Sushant Gupta
fonte
@SushantGupta - O que você quer dizer com 'mapeamentos de URL existenciais válidos?'
Jonathan Bechtel
@JonathanBechtel Como no bloco de código acima, após as rotas de URL não erradas.
precisa
6

Na última linha do app.js, basta colocar esta função. Isso substituirá a página de erro padrão de página não encontrada:

app.use(function (req, res) {
    res.status(404).render('error');
});

Ele substituirá todas as solicitações que não possuem um manipulador válido e renderiza sua própria página de erro.

Vivek Bajpai
fonte
2
Foi o seu comentário da "última linha do app.js" que ajudou! Obrigado!
C0NFUS3D 7/08
Adicionado um recurso ao meu aplicativo. Obrigado :)
Pramesh Bajracharya
5

A resposta para sua pergunta é:

app.use(function(req, res) {
    res.status(404).end('error');
});

E há um ótimo artigo sobre por que é o melhor caminho aqui .

Marius Cotofana
fonte
1
Qual é a diferença entre sende end?
Timo Huovinen
Eu acho que ele tem miss-write deve sersend
Zaid abu khalaf 01 de
4

Express-Error-Handler permite especificar modelos personalizados, páginas estáticas ou manipuladores de erros para seus erros. Ele também faz outras coisas úteis para o tratamento de erros que todo aplicativo deve implementar, como proteção contra ataques de erro 4xx do DOS e desligamento normal devido a erros irrecuperáveis. Veja como você faz o que está pedindo:

var errorHandler = require('express-error-handler'),
  handler = errorHandler({
    static: {
      '404': 'path/to/static/404.html'
    }
  });

// After all your routes...
// Pass a 404 into next(err)
app.use( errorHandler.httpError(404) );

// Handle all unhandled errors:
app.use( handler );

Ou para um manipulador personalizado:

handler = errorHandler({
  handlers: {
    '404': function err404() {
      // do some custom thing here...
    }
  }
}); 

Ou para uma visualização personalizada:

handler = errorHandler({
  views: {
    '404': '404.jade'
  }
});
Eric Elliott
fonte
4

Há alguns casos em que a página 404 não pode ser gravada para ser executada como a última rota, especialmente se você tiver uma função de roteamento assíncrona que traz uma rota / atrasada para a parte. O padrão abaixo pode ser adotado nesses casos.

var express = require("express.io"),
    app = express(),
    router = express.Router();

router.get("/hello", function (req, res) {
    res.send("Hello World");
});

// Router is up here.
app.use(router);

app.use(function(req, res) {
    res.send("Crime Scene 404. Do not repeat");
});

router.get("/late", function (req, res) {
    res.send("Its OK to come late");
});

app.listen(8080, function (){
    console.log("Ready");
});
Dennis Mathew Philip
fonte
2
Brilhante, obrigado! A única resposta (?) Que não depende do processamento linear de express (por exemplo, "basta colocar o manipulador de erros no final").
Nick Grealy
2
// Add this middleware
// error handler
app.use(function(err, req, res, next) {
 // set locals, only providing error in development
   res.locals.message = err.message;
   res.locals.error = req.app.get('env') === 'development' ? err : {};

 // render the error page
   res.status(err.status || 500);
   res.render('error');
  });
ASHISH RANJAN
fonte
2

A maneira mais fácil de fazer isso é capturar tudo na página de erro

// Step 1: calling express
const express = require("express");
const app = express();

Então

// require Path to get file locations
const path = require("path");

Agora você pode armazenar todas as suas páginas "html" (incluindo um erro "página" html)) em uma variável

// Storing file locations in a variable
var indexPg = path.join(__dirname, "./htmlPages/index.html");
var aboutPg = path.join(__dirname, "./htmlPages/about.html");
var contactPg = path.join(__dirname, "./htmlPages/contact.html");
var errorPg = path.join(__dirname, "./htmlPages/404.html"); //this is your error page

Agora você simplesmente chama as páginas usando o método Get e captura todas as rotas não disponíveis para direcionar para sua página de erro usando app.get ("*")

//Step 2: Defining Routes
//default page will be your index.html
app.get("/", function(req,res){
  res.sendFile(indexPg);
});
//about page
app.get("/about", function(req,res){
  res.sendFile(aboutPg);
});
//contact page
app.get("/contact", function(req,res){
  res.sendFile(contactPg);
});
//catch all endpoint will be Error Page
app.get("*", function(req,res){
  res.sendFile(errorPg);
});

Não se esqueça de configurar uma porta e escutar para o servidor:

// Setting port to listen on
const port = process.env.PORT || 8000;
// Listening on port
app.listen(port, function(){
  console.log(`http://localhost:${port}`);
})

Agora, isso deve mostrar sua página de erro para todos os pontos de extremidade não reconhecidos!

Kean Amaral
fonte
1

Embora as respostas acima estejam corretas, para aqueles que desejam que isso funcione no IISNODE, você também precisa especificar

<configuration>
    <system.webServer>
        <httpErrors existingResponse="PassThrough"/>
    </system.webServer>
<configuration>

no seu web.config (caso contrário, o IIS consumirá sua saída).

Laktak
fonte
2
Obrigado!!! Você é o único na internet que parece saber disso (ou pelo menos compartilhar isso)! Cheers
André Lucas
1

você pode manipular erros de acordo com o tipo de conteúdo

Além disso, manuseio de acordo com o código de status.

app.js

import express from 'express';

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// when status is 404, error handler
app.use(function(err, req, res, next) {
    // set locals, only providing error in development
    res.locals.message = err.message;
    res.locals.error = req.app.get('env') === 'development' ? err : {};

    // render the error page
    res.status(err.status || 500);
    if( 404 === err.status  ){
        res.format({
            'text/plain': () => {
                res.send({message: 'not found Data'});
            },
            'text/html': () => {
                res.render('404.jade');
            },
            'application/json': () => {
                res.send({message: 'not found Data'});
            },
            'default': () => {
                res.status(406).send('Not Acceptable');
            }
        })
    }

    // when status is 500, error handler
    if(500 === err.status) {
        return res.send({message: 'error occur'});
    }
});

404.jade

doctype html

html
  head
    title 404 Not Found

    meta(http-equiv="Content-Type" content="text/html; charset=utf-8")
    meta(name = "viewport" content="width=device-width, initial-scale=1.0 user-scalable=no")

  body
      h2 Not Found Page
      h2 404 Error Code

Se você pode usar o res.format, pode escrever um código simples de tratamento de erros.

Recomendação em res.format()vez deres.accepts() .

Se o erro 500 ocorrer no código anterior, if(500 == err.status){. . . }será chamado

멍개 -mung
fonte
1

Olá, por favor encontre a resposta

const express = require('express');
const app = express();
const port = 8080;

app.get('/', (req, res) => res.send('Hello home!'));
app.get('/about-us', (req, res) => res.send('Hello about us!'));
app.post('/user/set-profile', (req, res) => res.send('Hello profile!'));
//last 404 page 
app.get('*', (req, res) => res.send('Page Not found 404'));
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Krishnamoorthy Acharya
fonte
0

Se você usar o pacote express-generator:

próximo (err);

Este código envia você para o middleware 404.

Josué Díaz
fonte
0

Para enviar para uma página personalizada:

app.get('*', function(req, res){
  if (req.accepts('html')) {
     res.send('404', '<script>location.href = "/the-404-page.html";</script>');
     return;
  }
});
Kristian
fonte
0

Eu usei o manipulador abaixo para lidar com o erro 404 com um .ejsarquivo estático .

Coloque esse código em um script de rota e, em seguida, exigem que file.jsatravés app.use()da sua app.js/ server.js/www.js (se estiver usando IntelliJ para NodeJS)

Você também pode usar um .htmlarquivo estático .

//Unknown route handler
 router.get("[otherRoute]", function(request, response) {
     response.status(404);
     response.render("error404.[ejs]/[html]");
     response.end();
 });

Dessa forma, o servidor expresso em execução responderá com uma adequada 404 errore seu site também poderá incluir uma página que exibe corretamente a resposta 404 do servidor. Você também pode incluir um navbarem que 404 error templateque os links para outros conteúdos importantes do seu site.

mudrak patel
fonte
0

Se você deseja redirecionar para páginas de erro de suas funções (rotas), faça o seguinte:

  1. Adicione código geral de mensagens de erro no seu app.js -

    app.use(function(err, req, res, next) {
        // set locals, only providing error in development
        res.locals.message = err.message
        res.locals.error = req.app.get('env') === 'development' ? err : {}
    
        // render the error page
        // you can also serve different error pages
        // for example sake, I am just responding with simple error messages 
        res.status(err.status || 500)
       if(err.status === 403){
           return res.send('Action forbidden!');
       }
    
       if(err.status === 404){
           return res.send('Page not found!');
       }
    
       // when status is 500, error handler
       if(err.status === 500) {
           return res.send('Server error occured!');
       }
       res.render('error')
    })
  2. Em sua função, em vez de usar um redirecionamento de página de erro, você pode definir primeiro o status do erro e, em seguida, usar next () para que o fluxo de código passe pelo código acima -

    if(FOUND){
        ...
    }else{
        // redirecting to general error page
        // any error code can be used (provided you have handled its error response)
        res.status(404)
        // calling next() will make the control to go call the step 1. error code
        // it will return the error response according to the error code given (provided you have handled its error response)
        next()
    }
Anshul Bisht
fonte
0

A página 404 deve ser configurada imediatamente antes da chamada para app.listen.Express ter suporte para * nos caminhos da rota. Este é um caractere especial que corresponde a qualquer coisa. Isso pode ser usado para criar um manipulador de rota que corresponda a todas as solicitações.

app.get('*', (req, res) => {
  res.render('404', {
    title: '404',
    name: 'test',
    errorMessage: 'Page not found.'
  })
})
Rajat
fonte
0

Cobertura de todos os verbos HTTP em express

Para cobrir todos os verbos HTTP e todos os caminhos restantes, você pode usar:

app.all('*', cb)

A solução final ficaria assim:

app.all('*', (req, res) =>{
    res.status(404).json({
        success: false,
        data: '404'
    })
})

Você não deve esquecer de colocar o roteador no final. Porque a ordem dos roteadores é importante.

NGS
fonte
0

O código acima não funcionou para mim.

Então eu encontrei uma nova solução que realmente funciona!

app.use(function(req, res, next) {
    res.status(404).send('Unable to find the requested resource!');
});

Ou você pode até renderizá-lo em uma página 404.

app.use(function(req, res, next) {
    res.status(404).render("404page");
});

Espero que isso tenha ajudado!

John Tasci
fonte
-3
app.get('*',function(req,res){
 res.redirect('/login');
});
s srinivas
fonte