AngularJS и обработка 404 ошибок

каков наилучший способ обслуживать правильные 404 с приложением AngularJS?

немного фона: я строю Угловое приложение и решил использовать

$locationProvider.html5Mode(true);

потому что я хочу, чтобы URL-адреса казались естественными (и неотличимыми от многостраничного "традиционного" веб-приложения).

на стороне сервера (простое приложение Python Flask) у меня есть обработчик catch-all, который перенаправляет все в угловое приложение:

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

Теперь, я пытаюсь выяснить что делать с 404 ошибками. Большинство угловых приложений, которые я видел, делают следующее:

.otherwise({ redirectTo: '/' })

что означает, что нет никакого способа, которым они могут обслуживать правильный 404.

однако я бы предпочел вернуть правильный 404, с кодом статуса 404 (в основном для целей SEO).

каков наилучший способ обработки 404s с угловым? Не стоит ли мне беспокоиться об этом и придерживаться уловки? Или я должен удалить catch-all и обслуживать правильные 404 на сервере сторона?

отредактированы для ясности

5 ответов


Я думаю, вы путаете маршруты колбы с угловыми маршрутами.

код ошибки 404 является частью протокола HTTP. Веб-сервер использует его в качестве ответа клиенту, если запрошенный URL-адрес не известен серверу. Поскольку вы помещаете catch-all в свой сервер Flask, вы никогда не получите 404, Flask вызовет вашу функцию просмотра для любых URL-адресов, которые вы вводите в адресной строке. На мой взгляд, у вас не должно быть catch-all и просто дайте колбе ответить 404, когда пользователь вводит недопустимый URL в адресной строке, в этом нет ничего плохого. Flask даже позволяет отправлять пользовательскую страницу при возврате кода 404, поэтому вы можете сделать страницу ошибки похожей на остальную часть вашего сайта.

на угловой стороне действительно нет транзакции HTTP, потому что вся внутренняя маршрутизация приложения происходит в клиенте без ведома сервера. Это может быть частью вашей путаницы, угловые ссылки обрабатываются полностью в клиенте без каких-либо запросов сервер даже в html5mode, поэтому в этом контексте нет концепции ошибки 404, просто потому, что нет участия сервера. Угловая ссылка, которая отправляет вас на неизвестный маршрут, просто попадет в otherwise предложения. Правильная вещь здесь - либо показать сообщение об ошибке (если пользователь должен знать об этом условии и может что-то сделать), либо просто игнорировать неизвестный маршрут, как redirectTo: '/' делает.

это, похоже, не ваш случай, но если в дополнение к обслуживание углового приложения ваш сервер реализовал API, который Angular может использовать во время работы, тогда Angular может получить 404 от Flask, если он сделал асинхронный запрос к этому API, используя недопустимый URL. Но вы не хотели бы показывать пользователю страницу ошибки 404, если это произошло, так как запрос был внутренним для приложения и не запускался пользователем напрямую.

Я надеюсь, это поможет прояснить ситуацию!


поиграв немного, а также обсудив некоторые вопросы с Мигелем, я собрал несколько разных решений:

  1. просто используйте catch-all и не беспокойтесь о правильных 404-х. Это можно настроить с помощью кода на стороне сервера (как в моем исходном решении) или лучше с перезаписью URL-адреса на вашем веб-сервере.
  2. зарезервировать определенный раздел вашего сайта для вашего углового приложения (например,/app). Для этого раздела настройте catch-all и не беспокойтесь о правильных 404. Твой другие страницы будут обслуживаться как обычные страницы и посещать любой недопустимый URL, который не начинается с /app приведет к правильному 404.
  3. непрерывно убедитесь, что все ваши маршруты в приложении.js зеркально отражаются в вашем коде на стороне сервера (да, довольно раздражает), где вы будете иметь эти маршруты обслуживать свое угловое приложение. Все остальные маршруты будут 404.

п. с. второй вариант-это мой личный фаворит. Я пробовал это, и это работает довольно хорошо.


Это старый поток, но я пересекаю его во время поиска ответа.

добавить в конце вашего appRoutes.js и сделайте 404.представление html.

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

.otherwise({ redirectTo: '/404' })

Я думаю, что настоящий http 404 будет довольно бесполезным "для целей SEO", если вы не обслуживаете полезный контент без javascript для реальных страниц вашего сайта. Индексатор поиска вряд ли сможет отобразить ваш угловой сайт для индексирования.

Если вы беспокоитесь о SEO, вам понадобится какой-то серверный способ рендеринга контента, который ваши угловые страницы рендеринга. Если у вас есть это, добавление 404s для недопустимых URL-адресов является самой простой частью проблемы.


вот лучший способ справиться с ошибкой и работает хорошо

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'
        })

        ......

   };