AngularJS 和处理 404 错误

Posted

技术标签:

【中文标题】AngularJS 和处理 404 错误【英文标题】:AngularJS and Handling 404 Errors 【发布时间】:2013-07-05 08:28:45 【问题描述】:

使用 AngularJS 应用程序提供正确的 404 的最佳方式是什么?

一点背景知识:我正在构建一个 Angular 应用程序并选择使用

$locationProvider.html5Mode(true);

因为我希望 URL 看起来自然(并且与多页“传统”网络应用程序没有区别)。

在服务器端(一个简单的 Python Flask 应用程序),我有一个包罗万象的处理程序,可以将所有内容重定向到 Angular 应用程序:

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

现在,我正试图弄清楚如何处理 404 错误。我见过的大多数 Angular 应用程序都执行以下操作:

.otherwise( redirectTo: '/' )

这意味着他们无法提供正确的 404。

但是,我更愿意返回正确的 404,带有 404 状态代码(主要用于 SEO 目的)。

使用 Angular 处理 404 的最佳方法是什么?我应该不担心它并坚持一个包罗万象的事情吗?或者我应该删除所有内容并在服务器端提供正确的 404?

为清晰起见进行了编辑

【问题讨论】:

你想在 404 上做什么,能不能提一下你的用例 当访问/asdf时,应该被带到一个404页面:“对不起,你试图访问的页面不存在”。应该返回一个 404 状态码。 您可以注册一个响应拦截器并检查拦截器中的状态代码,如果您在 http 状态代码中找到 404,您可以使用 $location.path('path') 重定向到任何路径 【参考方案1】:

这是一个旧线程,但我在寻找答案时遇到了它。

将此添加到您的 appRoutes.js 的末尾并创建一个 404.html 视图。

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

.otherwise( redirectTo: '/404' )

【讨论】:

【参考方案2】:

我认为,如果您没有为网站的真实页面提供可用的非 javascript 内容,那么“出于 SEO 目的”,真正的 http 404 将毫无用处。搜索索引器不太可能呈现您的 Angular 网站以进行索引。

如果您担心 SEO,您将需要某种服务器端方式来呈现您的 Angular 页面正在呈现的内容。如果你有,为无效 URL 添加 404 是问题中最简单的部分。

【讨论】:

【参考方案3】:

在玩了一会儿之后,以及与 Miguel 的一些讨论,我整理了一些不同的解决方案:

    只需使用包罗万象的方法,不必担心正确的 404。这可以使用服务器端代码进行设置(就像我的原始解决方案一样),或者更好的是,在您的网络服务器上重写 URL。 为您的 Angular 应用程序保留您网站的某个部分(例如 /app)。对于本节,设置一个包罗万象的内容,不要担心正确的 404。您的其他页面将作为常规页面提供,访问任何不以 /app 开头的无效 URL 将导致正确的 404。 不断确保 app.js 中的所有路由都反映在服务器端代码中(是的,这很烦人),在那里您可以让这些路由为您的 Angular 应用程序提供服务。所有其他路线将 404。

附:第二个选项是我个人最喜欢的。我已经试过了,效果很好。

【讨论】:

我遇到了与 angular / node.js 堆栈类似的问题。我有一条使用特定 ID 进行数据查找的路由。对于一个好的 URL,这很好用。对于一个糟糕的 URL,我只会看到一个看起来很糟糕的网页。 url 看起来像:/details/goodID 与 details/badID(我还注意到某些机器人喜欢尝试 /details/details/goodID,这也是一条糟糕的路线:/)。解决方案 #2 并不能真正处理这种情况,如果可能的话,我想避免 #3。你有没有遇到任何其他想法?是否有 404-ish 方式来报告错误客户端?? @Ryan - 关于#3,通过 browserify 需要一个包含所有定义的路由模块不是很糟糕吗?反正我就是这么干的。 @Ryan 请原谅我,但是这个服务器调用是否否定了客户端 SPA 的全部意义?我们调用一次 SPA 并从那里通过 Ajax 使用 Api。如果您必须为每个端点访问您的服务器,那么为什么不简单地使用客户端/服务器模型呢?【参考方案4】:

这是处理错误的最佳方法,并且效果很好

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

        ......

   ;

【讨论】:

我没有投反对票 - 但我知道 SO 更喜欢不是严格代码的答案。只是一个建议,因为我感谢大多数花时间回答他人问题的人。 这是“我如何拦截并处理 angularjs 中的所有 404 错误”问题的答案。我正在寻找这个但找不到它,我知道我正在寻找的是如何为所有 $http 调用添加一个拦截器,因为没有这个,angularjs 不会将 404 视为错误,就像另一个代码和它一样将在承诺中解决。我需要一种自动错误所有 404 的方法,以便我可以捕获它们,例如在登录失败时返回 404 的登录中。希望它可以帮助某人#angularjs #httpinterceptor #interceptor【参考方案5】:

我认为您将 Flask 路由与 Angular 路由混淆了。

404 错误代码是 HTTP 协议的一部分。当服务器不知道请求的 URL 时,Web 服务器将其用作对客户端的响应。因为你在你的 Flask 服务器中放了一个包罗万象的东西,你永远不会得到 404,Flask 将为你在地址栏中键入的任何 URL 调用你的视图函数。在我看来,当用户在地址栏中输入无效的 URL 时,你不应该让 Flask 以 404 响应,这没有什么问题。 Flask 甚至允许您在返回 404 代码时发送自定义页面,因此您可以使错误页面看起来像您网站的其余部分。

在 Angular 方面,实际上没有 HTTP 事务,因为应用程序内部的所有路由都发生在客户端,而服务器甚至都不知道。这可能是您混淆的一部分,Angular 链接完全在客户端处理,即使在 html5 模式下也没有向服务器发出任何请求,因此在这种情况下没有 404 错误的概念,仅仅是因为没有服务器参与。将您发送到未知路线的 Angular 链接将落入otherwise 子句中。此处正确的做法是显示错误消息(如果用户需要了解此情况并可以对此采取措施)或只是忽略未知路线,就像 redirectTo: '/' 所做的那样。

这似乎不是你的情况,但如果除了为 Angular 应用程序提供服务之外,你的服务器还实现了一个 Angular 可以在运行时使用的 API,那么如果 Angular 向它发出异步请求,它可能会从 Flask 获得 404 API 使用了无效的 URL。但是,如果发生这种情况,您不希望向用户显示 404 错误页面,因为该请求是应用程序内部的,而不是由用户直接触发的。

我希望这有助于澄清情况!

【讨论】:

我将删除全部内容,因为我希望能够处理正确的 404 错误(对于 SEO 等)。但是,现在我必须保留 Flask 传递给 Angular 的路由列表。这意味着每当我添加一个新路由时,我都需要将它添加到我的 app.js 和我的 controllers.py 中。但老实说,我只想说实话。如何在一个位置更新路由并让它们在 JS 和 python 代码中自动反映?我正在考虑使用路由创建一个 JSON 文件(python 将导入路由,并且在触摸 JSON 文件时会生成一个新的 app.js)。 你还在混淆服务器端和客户端。您的 Flask 应用程序只有一个路由,"/" 将 Angular 应用程序提供给客户端。而已。 Angular 应用程序可以根据需要定义任意数量的路由,但这些路由是客户端,Flask 服务器不参与其中。事实上,通过如此简单的设置,我不清楚为什么您需要在服务器上安装 Flask,看来您只是为您的 Angular 应用程序提供静态文件。 @Miguel 我没有混淆他们。考虑一下:我的角度应用程序在角度路线中带有“/”和“/about”。我也启用了 html5Mode。这意味着如果用户转到“/”,则会向服务器发送一个请求,然后启动 Angular 应用程序。当用户导航到“/about”时,请求不会转到服务器,因为 Angular 应用程序现在正在处理它。但是,如果用户刷新页面,“/about”将被发送到服务器。这意味着,服务器上需要有一个“/about”端点将请求传递到 angular。 抱歉,是的,如果您希望用户从地址栏中显示的任何链接访问应用程序,那么您必须配置服务器以将所有这些 URL 重写为“/”所以始终提供主应用程序。刚刚在关于 html5 模式的 Angular 文档中找到了这一点:“使用这种模式需要在服务器端重写 URL,基本上你必须重写所有指向应用程序入口点的链接(例如 index.html)” 我想指出,上面的答案是不正确的,并且错误地表明我的困惑根本不存在。很高兴在答案的开头反映这一点。

以上是关于AngularJS 和处理 404 错误的主要内容,如果未能解决你的问题,请参考以下文章

Express + AngularJS + HTML:ng-include 不起作用(404 - 找不到页面错误)

AngularJS在HTML5模式下路由404错误

AngularJS - 删除Hashbang后页面重新加载时出现404错误[重复]

AngularJS - 为啥更改 url 地址时 $routeProvider 似乎不起作用并且我收到 404 错误

AngularJS API

如果将静态内容部署为 jar,则 Spring Boot 404 错误