¿Cómo redirigir los errores 404 a una página en ExpressJS?

203

No conozco una función para hacer esto, ¿alguien sabe de una?

hexacianuro
fuente

Respuestas:

274

Encontré este ejemplo bastante útil:

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

Entonces, en realidad es 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
fuente
Por favor, define "manejado"? ¿Qué marca exactamente la ruta como manejada?
Timo Huovinen
1
Supuse que no se encontró una ruta coincidente hasta ese punto.
Felix
2
Para su información, el uso de app.routerahora está en desuso. Ver github.com/strongloop/express/wiki/…
iX3
2
Para la respuesta JSON puede ser mejor usar en res.jsonlugar de res.send(). Se comportarían igual en su código, pero el uso res.jsonhará algo de magia en la conversión automática de objetos en cadenas donde .send()no lo hará. Más vale prevenir que lamentar. expressjs.com/api.html#res.json
wgp
9
Ahora esta pregunta aparece en las preguntas frecuentes expressjs.com/starter/faq.html#how-do-you-handle-404s-
Ivan Fraixedes
158

Creo que primero debes definir todas tus rutas y como la última ruta agregar

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

Una aplicación de ejemplo 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?
Alfredo
fuente
66
Bueno ... el problema es que el "*" coincide con los archivos .js y .css, y no están especificados en la aplicación ... bueno, no sé si hay alguna forma de detectar exactamente el Lo mismo que el error 404, o una forma de sobrescribir el mensaje "No se puede ...". De todos modos, gracias
1
¿Está utilizando middleware estático porque aún puede servir archivos estáticos?
Alfred
44
app.get('/public/*', function(req, res){ res.sendfile(__dirname + '/public/' + req.url); })Puede utilizar esta ruta para enviar archivos estáticos. funciona bien con la ruta "*" anterior. app.use(express.static(__dirname + '/public'));no funciona para mí, por cable.
Chris
25
Esto no estaba funcionando para mí, pero luego descubrí que app.use(express.static(...))vino después app.use(app.router). Una vez que los cambié, todo salió bien.
Stephen
55
+1 por agregar el comentario de @ Stephen a su respuesta. Esto tampoco funcionó para mí hasta que puse app.use (app.router) DESPUÉS de app.use (express.static (...))
braitsch
37

Puede colocar un middleware en la última posición que arroje un NotFounderror,
o incluso muestre la página 404 directamente:

app.use(function(req,res){
    res.status(404).render('404.jade');
});
Ganesh Kumar
fuente
9
Considere una respuesta un poco más detallada la próxima vez ... Los ejemplos generalmente están bien, y este es un buen ejemplo, pero alguna explicación puede ser muy, muy buena también ...
Tonny Madsen
2
+1 Muy bien! Creo que esto es mejor que una última ruta, porque de esa manera no tiene que use()tu app.routeren el último tiempo. (como en mi caso)
Alba Mendez
Además, esto reemplaza el comportamiento predeterminado en cualquier solicitud (no solo GETs). Intente con POSTuna URL aleatoria con el otro método; devolverá el valor predeterminado Cannot POST.... Un atacante sabría que estás usando Express.JS.
Alba Méndez
Muy bien, excepto usar ejs, solo tienes que ponerlores.render('404')
locrizak
Esto probablemente también debería tener un estado (404) res.status (404) .render ('404')
MartinWebb
32

Las respuestas anteriores son buenas, pero en la mitad de estas no obtendrá 404 cuando se devuelva su código de estado HTTP y en la otra mitad, no podrá tener una plantilla personalizada renderizada. La mejor manera de tener una página de error personalizada (404) en Expressjs es

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

Coloque este código al final de todas sus asignaciones de URL.

Sushant Gupta
fuente
@SushantGupta: ¿qué quiere decir con "asignaciones de URL existenciales válidas"?
Jonathan Bechtel
@JonathanBechtel Como en tener el bloque de código anterior después de sus rutas URL no erróneas.
Sushant Gupta
6

En la última línea de app.js simplemente pon esta función. Esto anulará la página de error predeterminada de página no encontrada:

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

Anulará todas las solicitudes que no tengan un controlador válido y generará su propia página de error.

Vivek Bajpai
fuente
2
¡Fue su comentario de "última línea de app.js" lo que ayudó! ¡Gracias!
C0NFUS3D
Se agregó una función a mi aplicación. Gracias :)
Pramesh Bajracharya
5

La respuesta a tu pregunta es:

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

Y hay un gran artículo sobre por qué es la mejor manera aquí .

Marius Cotofana
fuente
1
¿Cuál es la diferencia entre sendy end?
Timo Huovinen
Creo que tiene una send
mala
4

express-error-handler le permite especificar plantillas personalizadas, páginas estáticas o manejadores de errores para sus errores. También hace otras cosas útiles para el manejo de errores que toda aplicación debería implementar, como proteger contra los ataques de error 4xx de DOS y el apagado correcto de errores irrecuperables. Así es como haces lo que estás pidiendo:

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 );

O para un controlador personalizado:

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

O para una vista personalizada:

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

Hay algunos casos en los que la página 404 no se puede escribir para ejecutarse como la última ruta, especialmente si tiene una función de enrutamiento asíncrono que trae una ruta / tarde a la fiesta. El siguiente patrón podría adoptarse en esos 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
fuente
2
Genial, gracias! La única respuesta (?) Que no se basa en el procesamiento lineal de express (es decir, "simplemente coloque el controlador de errores al 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');
  });
RANJAN CENIZO
fuente
2

La forma más fácil de hacerlo es tener un catch all para la página de error

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

Luego

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

Ahora puede almacenar todas sus páginas "html" (incluida una página de error "html") en una variable

// 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

Ahora simplemente llame a las páginas con el Método Get y obtenga una captura de todas las rutas que no estén disponibles para dirigirlas a su página de error 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);
});

No olvide configurar un puerto y escuchar el servidor:

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

¡Ahora debería mostrar su página de error para todos los puntos finales no reconocidos!

Kean Amaral
fuente
1

Si bien las respuestas anteriores son correctas, para aquellos que desean que esto funcione en IISNODE, también deben especificar

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

en su web.config (de lo contrario, IIS se comerá su salida).

laktak
fuente
2
¡¡¡Gracias!!! ¡Eres el único en Internet que parece saberlo (o al menos compartirlo)! aplausos
André Lucas
1

puede cometer errores de acuerdo con el tipo de contenido

Además, manejo de acuerdo con el código de estado.

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

Si puede usar res.format, puede escribir un código simple de manejo de errores.

Recomendación en res.format()lugar de res.accepts().

Si el error 500 ocurre en el código anterior, if(500 == err.status){. . . }se llama

멍개 -mung
fuente
1

Hola por favor encuentra la respuesta

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
fuente
0

Si usa el paquete express-generator:

siguiente (err);

Este código lo envía al middleware 404.

Josué Díaz
fuente
0

Para enviar a una 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
fuente
0

Usé el siguiente controlador para manejar el error 404 con un .ejsarchivo estático .

Pon este código en un script ruta y luego requerir que file.jsa través app.use()de su app.js/ server.js/ www.js(si se utiliza para IntelliJ NodeJS)

También puedes usar un .htmlarchivo estático .

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

De esta manera, el servidor express en ejecución responderá con una respuesta adecuada 404 errory su sitio web también puede incluir una página que muestre correctamente la respuesta 404 del servidor. También puede incluir una navbaren la que 404 error templateque los enlaces a otros contenidos importantes de su sitio web.

mudrak patel
fuente
0

Si desea redirigir a páginas de error desde sus funciones (rutas), haga lo siguiente:

  1. Agregue un código de mensaje de error general en su 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. En su función, en lugar de utilizar una redirección de página de error, puede establecer primero el estado del error y luego utilizar next () para que el flujo de código pase por el código anterior:

    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
fuente
0

La página 404 debe configurarse justo antes de la llamada a app.listen.Express tiene soporte para * en rutas de ruta. Este es un personaje especial que coincide con cualquier cosa. Esto se puede usar para crear un controlador de ruta que coincida con todas las solicitudes.

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

Cubriendo todos los verbos HTTP en express

Para cubrir todos los verbos HTTP y todas las rutas restantes, puede usar:

app.all('*', cb)

La solución final se vería así:

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

No debes olvidar poner el enrutador al final. Porque el orden de los enrutadores es importante.

NGS
fuente
0

El código anterior no funcionó para mí.

¡Así que encontré una nueva solución que realmente funciona!

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

O incluso puede representarlo en una página 404.

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

Espero que esto te haya ayudado!

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