【问题标题】:AngularJS UI router handling 404sAngularJS UI 路由器处理 404s
【发布时间】:2018-08-27 23:03:48
【问题描述】:

我有一个包含我的 API 调用的服务的应用程序:

var ConcernService = {
    ...
    get: function (items_url, objId) {
        var defer = $q.defer();
        $http({method: 'GET', 
            url: api_url + items_url + objId}).
            success(function (data, status, headers, config) {
                defer.resolve(data);
            }).error(function (data, status, headers, config) {
                console.log('ConcernService.get status',status);
                defer.reject(status);
            });
        return defer.promise;
    },

我正在使用 UI-Router 在状态之间转换:

concernsApp

    .config( function ($stateProvider, $urlRouterProvider) {

        $urlRouterProvider.otherwise("/404/");


        $stateProvider.state('project', {
        url: '/project/:projectId/',
        resolve: {
            project: function ($stateParams, ConcernService) {
                return ConcernService.get('projects/', $stateParams.projectId);
            },
        },
        views: {
            ...
        }
    });

我不再使用普通的 AngularJS 路由器,但我很难理解如何实现 404。我可以看到ConcernService 将console.log 状态抛出为被拒绝,但是我如何在状态路由器中捕获它?

【问题讨论】:

    标签: angularjs angular-ui-router


    【解决方案1】:

    otherwise() 规则仅在没有其他 路由 匹配时调用。您真正想要的是拦截$stateChangeError 事件,这是在状态转换中出现问题时触发的事件(例如,解析失败)。您可以在state change event docs 中阅读更多相关信息。

    你想要做的最简单的实现是这样的:

    $rootScope.$on('$stateChangeError', function(event) {
      $state.go('404');
    });
    

    另外,由于$http 本身是建立在承诺之上的(resolve 解决了),所以您的 ConcernService 方法可以简化为单行(我意识到您出于调试目的对其进行了扩展,但您可以就像很容易链接它一样,仅供参考):

    var ConcernService = {
    
      get: function (items_url, objId) {
        return $http.get(api_url + items_url + objId);
      }
    }
    

    【讨论】:

    • 对,像这样处理 404 完全有道理。但是,对于 $http,如果我像您一样实现它,如果 objId 来自 $stateParams 并且尚未解决,则它无法正常工作。这不就是defer 方法的用途吗?
    • 我不太确定您的意思,但是当您将 $stateParams 注入到 resolve 或 onEnter 函数中时,您会得到一个本地副本,表示正在转换到的状态的参数。
    • @NateAbele 请问您是如何将 $state 注入事件处理程序的:$stateChangeError?因为我有错误:你的例子中的'undefined $state'。
    • @Roylee 你把它注入到你注入$rootScope的同一个函数中。例如:yourModuleName.run(function($rootScope, $state) { /* ... */ });
    • @XelharK 取决于您的用例。也许用户点击了一个链接,从该链接中提取参数并将其注入 API 调用,该调用返回 404。在这种情况下,“未找到”错误将完全适合显示(但是,这有点争议,因为 HTTP 错误代码/消息与 SPA 完全正交)。
    【解决方案2】:

    我在两个 404 状态之间有所不同:

    服务器:

    • 根据服务器响应 HTTP 代码 404 显示 404 页面
    • 重要的是定义 no URL,以便用户停留在发生错误的 URL 上

    客户:

    • Angular ui 路由器找不到 URL(没有定义的 URL)

    Angular UI-Router 状态的代码:

    $stateProvider
      .state('404server', {
        templateUrl: '/views/layouts/404.html'
      })
      .state('404client', {
        url: '*path',
        templateUrl: '/views/layouts/404.html'
      });
    

    $httpProvider拦截器中的代码:

    if(response.status === 404) {
      $injector.get('$state').go('404server');
    }
    

    为什么我使用$injector 而不是$state 解释了here。

    【讨论】:

    • 您应该中止当前转换$state.transition.abort()。否则,您将看到 Transition Rejection The transition has been superseded by a different transition
    【解决方案3】:

    您也可以尝试类似的方法,看看它是否适合您。您可能需要根据自己的需要进行调整:

    .state('otherwise', {
        abstract: true,
        templateUrl: 'views/404.html'
    })
    .state('otherwise.404', {
        url: '*path',
        templateUrl: 'views/404.html'
    })
    

    【讨论】:

    • 我不明白你为什么需要那个抽象的路线,你可以用一个状态来完成?
    • 它在没有抽象路线的情况下对我有用。我只有.state('notFound' { url: '*path', templateUrl: 'views/404.html' })
    【解决方案4】:

    $urlRouterProvider 仅像 $watch 到 $location 一样工作,如果实际 URL 与 .config() 函数中定义的规则之一匹配,那么它将重定向到指定的路由。

    这是我的建议,将“/404/”定义为状态:

    $stateProvider.state('404', {
      url:'/404/',
      views:{
          ...
      }
    });
    

    并且在reject()函数内部移动到404状态

     if(status == '404'){
       $state.transitionTo('404');
     }
    

    您必须添加 ui-router 作为项目模块的依赖项并在控制器中使用 $state 提供程序才能使用 $state.transitionTo()

    这里有一些信息:https://github.com/angular-ui/ui-router/wiki/Quick-Reference#statetransitiontoto-toparams--options

    【讨论】:

    • 在我的代码状态中似乎没有rejected 属性,它只相当于'404'。
    • 不好意思,我只是把它作为例子,让我更新代码。
    【解决方案5】:

    我设法在不使用 $urlRoutProvider 的情况下处理 404,因为我只通过测试 $state.transistion 来使用状态:

    angular.module("app", []).run(["$state", "$rootScope", function($state, $rootScope) => {
        $rootScope.$on("$locationChangeSuccess", function() {
            if (!$state.transition) {
                $state.go("404");
            }
        });
    }]);
    

    【讨论】:

      【解决方案6】:

      $urlRouterProvider.otherwise('/page-not-found');

      .state('error', {
        url: "/page-not-found",
        templateUrl: "templates/error.html",
        controller: "errorController"
      })
      

      将处理您的页面未找到问题。

      如果你想提高 404 发现故意使用 state 或 url。如果您想执行任何操作,我们已经创建了一个单独的控制器。

      【讨论】:

        猜你喜欢
        • 2017-03-16
        • 2023-03-30
        • 2016-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-08
        相关资源
        最近更新 更多