¿Cuál es la mejor manera de servir adecuada de 404 con una aplicación AngularJS?

Un poco de historia: estoy construyendo un Angular de la aplicación y han optado por usar

$locationProvider.html5Mode(true);

porque quiero que las direcciones Url de parecer natural (y indistinguible de un multi-página «tradicional» de la aplicación web).

En el lado del servidor (un simple Python Matraz app), tengo un catch-all controlador que redirige todo el angular de la aplicación:

@app.route('/', defaults={'path': ''})
@app.route('/<path>')
def index(path):
    return make_response(open('Ang/templates/index.html').read())

Ahora, estoy tratando de averiguar qué hacer con los errores 404. La mayoría de los Angular apps que he visto hacer a los siguientes:

.otherwise({ redirectTo: '/' })

lo que significa que no hay forma en que puede servir un adecuado 404.

Sin embargo, que me gustaría mucho volver una adecuada 404, con un código de estado 404 (principalmente para fines de SEO).

¿Cuál es la mejor manera de manejar 404 con Angular? No debo preocuparme y seguir con un catch-all? O debo quitar el catch-all y servir adecuada de 404 en el lado del servidor?

editado para mayor claridad

  • ¿qué quieres hacer en 404 podría mencionar el caso de uso
  • Cuando uno visita /asdf, uno debe ser llevado a una página de error 404: «lo sentimos, la página que está intentando acceder no existe». Un código de estado 404 debe ser devuelto.
  • usted puede registrar una respuesta interceptor y comprobar el código de estado en el interceptor es encontrar 404 en el código de estado http que usted puede redirigir a cualquier ruta usando $ubicación.path(‘path’)
InformationsquelleAutor Ryan | 2013-07-08

5 Comentarios

  1. 33

    Creo que estás confundiendo el Matraz de rutas con Angular rutas.

    El 404 código de error es parte del protocolo HTTP. Un servidor web se utiliza como una respuesta a un cliente cuando la dirección URL solicitada no es conocida por el servidor. Porque se pone en un cajón de sastre en el que su Frasco servidor de usted nunca conseguirá un 404, Frasco invocar su punto de vista de la función para cualquier Url que usted escriba en la barra de direcciones. En mi opinión, usted no debe tener un catch-all » y solo dejar el Frasco responder con 404 cuando el usuario escribe una dirección URL no válida en la barra de direcciones, no hay nada de malo con eso. Matraz incluso le permite enviar una página personalizada cuando un 404 código se devuelve, por lo que usted puede hacer que la página de error igual que el resto de su sitio.

    Sobre el Angular lado, no hay realmente ninguna HTTP transacción debido a que el direccionamiento interno de la aplicación que sucede en el cliente sin que el servidor aun sabiendo. Esto puede ser parte de su confusión, Angular enlaces se lleva a cabo enteramente en el cliente sin ningún tipo de peticiones realizadas al servidor, incluso en html5mode, por lo que no existe el concepto de un error 404 en este contexto, simplemente porque no hay ningún servidor de participación. Un Angular link que te manda a un desconocido ruta de caer dentro de la otherwise cláusula. Lo más apropiado para hacer aquí es mostrar un mensaje de error (si el usuario necesita saber acerca de esta condición y puede hacer algo al respecto) o simplemente ignorar la ruta desconocida, como la redirectTo: '/' hace.

    Esto no parece ser tu caso, pero si además de servir a los Angular de la aplicación el servidor implementa una API que Angulares pueden utilizar mientras se ejecuta, entonces Angular podría conseguir un 404 desde el Matraz de si se hizo una solicitud asincrónica a esta API utilizando una dirección URL no válida. Pero usted no desea mostrar una página de error 404 para el usuario en el caso que sucedió, ya que la solicitud fue interno de la aplicación y no se desencadena por el usuario directamente.

    Espero que esto ayude a aclarar la situación!

    • Voy a quitar el catch-all, porque quiero ser capaz de servir adecuada errores 404 (para SEO, etc.). Sin embargo, ahora tengo que mantener una lista de rutas para el Matraz de pasar a Angular. Eso significa que cada vez que agrego una nueva ruta, tengo que añadir a mi app.js y mi controllers.py. Pero honestamente, me gustaría un solo punto de la verdad. ¿Cómo hago para actualizar las rutas en un solo lugar y les han auto-refleja tanto en la JS y el código de python? Yo estaba pensando en crear un archivo JSON con las rutas (python tendría que importar las rutas y una nueva app.js se genera cuando el archivo JSON es tocado).
    • Todavía confuso el servidor y el cliente. Su Frasco aplicación sólo una ruta, la "/" que sirve el Angular de la aplicación para el cliente. Eso es todo. El Angular de la aplicación puede definir tantas rutas como sea necesario, pero los que están de lado de cliente, el Frasco servidor no está involucrado en los. De hecho, con un simple programa de instalación no está claro para mí por qué usted necesita Matraz en el servidor, parece que el solo hecho de servir los archivos estáticos para su Angular de la aplicación.
    • No estoy confuso ellos. Considere esto: yo tengo mi angulares de la aplicación con «/» y «/» en el ángulo de rutas. También tengo html5Mode habilitado. Eso significa que si el usuario va a «/», se enviará la petición al servidor y, a continuación, el angular de la aplicación se iniciará. Cuando el usuario navega a «/acerca de», la solicitud no se vaya al servidor, desde el ángulo de la aplicación es ahora en la actualidad el manejo de la misma. Sin embargo, si el usuario actualiza la página «/acerca de» se enviará al servidor. Que significa, que existe la necesidad de un «/acerca de» de extremo en el servidor en el que pasa la solicitud a angular.
    • Lo siento, sí, si desea que el usuario accede a la aplicación desde cualquiera de los enlaces que se muestran en la barra de direcciones, a continuación, usted tiene que configurar el servidor para volver a escribir todas esas direcciones para «/» así que el principal de la aplicación es siempre sirve. Acabo de encontrar esto en el Angular de la documentación relativa a html5 modo: «el Uso de este modo requiere la reescritura de URL en el lado del servidor, básicamente, usted tiene que reescribir todos sus enlaces a punto de entrada de la aplicación (por ejemplo, index.html)»
    • Exactamente. Y esto puede ser bastante molesto, ya que puede que se encuentre el cambio de una dirección URL en su Angular de código, pero se olvidan de hacerlo en el código del servidor. Tampoco es muy elegante. Aquí es lo que acabé haciendo: (1) poner el enrutamiento de la información en un archivo JSON (2) configurar mi servidor para extraer los puntos finales de las rutas y los puntos finales de retorno «index.html» (angular de manejar) (3) escribió un guión para volver a generar un nuevo app.js desde el archivo JSON cada vez que el servidor se inicia. — Sin embargo, en mi opinión, este es también bastante poco elegante y estoy bastante satisfecho. Deseo que había una mejor manera.
    • O puede simplemente seguir la sugerencia dada por el ángulo en que chicos y aplicar la reescritura de url, lo que parece más fácil y más limpio.
    • Eso es lo que había originalmente. Así «/» y «/sobre» sería volver «index.html». Sin embargo, como he dicho antes, usted todavía tiene que actualizar continuamente los extremos en dos lugares.
    • La reescritura de URL es algo que configurar en el servidor web, no en el Frasco. Usted puede tener Apache, nginx, etc. modificar el entrante Url, de modo que su Frasco servidor sólo se ve «/». Usted no está planeando implementar su sitio en el Matraz de servidor web, haga? Que no es un servidor de producción.
    • Sí me doy cuenta de que el Frasco web del servidor no es un servidor web de producción, por lo que utilizar Gunicorn y desplegar a Heroku. Alguna idea de cómo hacer esto con Heroku? ¿Cuál es el problema con tener el Matraz de servidor de devolver el único modelo para el Angular de la aplicación? La latencia?
    • gunicorn es una de las más básicos de un servidor, creo que se podría implementar de reescritura utilizando el pre_request gancho, pero nunca he probado, no sé si esto funciona. Creo que hemos recorrido un círculo completo, si usted tuvo que implementar esto en el Matraz (y parece que es la única opción razonable), entonces el catch-all de la ruta que se inicia con la mejor manera, porque no quiero tener el lado del cliente de las rutas de duplicados en el servidor. Usted nunca conseguirá un 404 desde el Matraz de entonces, y si un cliente costado de la ruta no es válida sólo puede redirigir de nuevo a «/» de angular, o mostrar un mensaje de error si se prefiere.
    • Yo de hecho no me gusta el catch-all idea, ya que como se dijo, un 404 no será servido. Lo que terminé haciendo fue tener Matraz de redirigir a los Angular de aplicación sólo si una ruta determinada existido. De lo contrario, sería un error 404. He diseñado mis rutas en una manera que tengo de hacer un mínimo de actualización en el lado del servidor – mi CRUD rutas de estilo redirigir a angular sólo si una determinada URL de extremo corresponde a un modelo definido (y si un IDENTIFICADOR se especifica, corresponde a un objeto existente en la db). Otras rutas como «/acerca de» acabo de incluir de forma individual.
    • Un acertijo! Si usted puede ejecutar JS en el lado del servidor, podría desplegar sus rutas de archivo js y en realidad invocar en el servidor para decidir si responder con HTTP 404… entonces usted no tiene que actualizar en dos lugares … pero tendría que instalarla en el servidor en el momento de añadir las rutas
    • Me gustaría que tenga a bien señalar que la respuesta anterior es incorrecto, y erróneamente indica la confusión de mi parte que simplemente no estaba allí. Sería bueno tener este se refleja en el comienzo de la respuesta.

  2. 17

    Después de jugar un poco, así como algunas conversaciones con Miguel, he recopilado una serie de diferentes soluciones:

    1. Sólo tiene que utilizar un catch-all » y no se preocupe acerca de la manera adecuada de 404. Esto se puede configurar con el código del lado del servidor (como en mi de la solución original), o mejor, con la dirección URL de la re-escritura en el servidor web.
    2. Reservar una cierta sección de su sitio web para su angular de la aplicación (como /app). Para esta sección, establecer un catch-all » y no se preocupe acerca de la manera adecuada de 404. Sus otras páginas se sirve como regular páginas y visitar cualquier dirección URL no válida que no se inicia con /app resultará en una adecuada 404.
    3. Continuamente asegúrese de que todas sus rutas en app.js se reflejan en el código del lado del servidor (sí, bastante molesto), donde tendrás esas rutas de servir a su angular de la aplicación. Todas las demás rutas de 404.

    P. S. La segunda opción es mi favorita. Yo lo he probado y funciona bastante bien.

    • Yo estoy en un problema similar con un angular / node.js de la pila. Tengo una ruta que utiliza un ID específico para la búsqueda de datos. Para una buena dirección URL este funciona bien. Por una mala dirección URL acabo de viento con un roto en busca página web. La url parece: /detalles/goodID vs detalles/badID (también he notado ciertos bots gustaría probar /details/detalles/goodID que también es una mala ruta :/). Solución #2 en realidad no controlar este caso, y me gustaría evitar #3 si es posible. Hizo ejecutar a través de cualquier otras ideas? Hay un 404-ish forma de informar del error del lado del cliente??
    • sobre #3, lo que requiere una de las rutas módulo con todas las definiciones a través de browserify no es tan mala la derecha? Que es como lo he venido haciendo de todos modos.
    • Perdóname, pero no esta de llamada de servidor de negar el punto de Cliente del SPA? Llamamos a un SPA una vez y el uso de la Api a través de Ajax a partir de ahí. Si usted tiene que ir a su servidor para cada endpoint entonces, ¿por qué no simplemente usar el modelo cliente/servidor?
  3. 2

    Este es un hilo viejo, pero me leva a través de ella, mientras que la búsqueda de la respuesta.

    Agregar esto al final de su appRoutes.js y hacer un 404.html ver.

    .when('/404', {
        templateUrl: 'views/404.html',
        controller: 'MainController'
    })
    
    .otherwise({ redirectTo: '/404' })
  4. 0

    Creo que un verdadero http 404 va a ser bastante inútil «para fines de SEO» si usted no está sirviendo utilizable sin javascript contenido real de las páginas de su sitio. Un indizador de búsqueda es poco probable que sea capaz de hacer que su angulares sitio para la indización.

    Si usted está preocupado acerca de SEO, usted necesitará algún tipo de server side manera de representar el contenido que sus angular páginas son la representación. Si usted tiene que, la adición de 404 para invalid Url es la parte más fácil del problema.

  5. -2

    Aquí es la mejor manera de manejar el error y funciona muy bien

    function ($routeProvider, $locationProvider, $httpProvider) {
        var interceptor = [
            '$rootScope', '$q', function (scope, $q) {
    
                function success(response) {
                    return response;
                }
    
                function error(response) {
                    var status = response.status;
    
                    if (status == 401) {
                        var deferred = $q.defer();
                        var req = {
                            config: response.config,
                            deferred: deferred
                        };
                        window.location = "/";
                    }
    
                    if (status == 404) {
                        var deferred = $q.defer();
                        var req = {
                            config: response.config,
                            deferred: deferred
                        };
                        window.location = "#/404";
                    }
                    // otherwise
                    //return $q.reject(response);
                    window.location = "#/500";
                }
    
                return function (promise) {
                    return promise.then(success, error);
                };
    
            }
        ];
        $httpProvider.responseInterceptors.push(interceptor);
    });
    
    // routes
    app.config(function($routeProvider, $locationProvider) {
        $routeProvider
            .when('/404', {
                templateUrl: '/app/html/inserts/error404.html',
                controller: 'RouteCtrl'
            })
            .when('/500', {
                templateUrl: '/app/html/inserts/error404.html',
                controller: 'RouteCtrl'
            })
    
            ......
    
       };
    • Yo no downvote – pero yo sé LO que prefiere respuestas que no son estrictamente de código. Sólo una sugerencia, ya que estoy agradecido por la mayoría de la gente que gasta su tiempo en contestar las preguntas de los demás.
    • Esto no se soluciona el problema…

Dejar respuesta

Please enter your comment!
Please enter your name here