AngularJS UI路由处理404错误

13

我有一个应用程序,其中包含一个服务,它封装了我的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将状态作为rejected抛出console.log,但我应该如何在状态路由器中捕获它呢?

6个回答

22
otherwise()规则仅在没有其他路由匹配时才会被调用。你真正想要的是拦截$stateChangeError事件,当状态转换出现问题时(例如,解析失败),它就会被触发。你可以在状态变更事件文档中了解更多信息。
你尝试实现的最简单方法如下:
$rootScope.$on('$stateChangeError', function(event) {
  $state.go('404');
});

另外,由于$http本身是基于promise构建的(resolve解决),因此您的ConcernService方法可以简化为一行代码(我知道您展开了它以进行调试,但您也可以轻松地链接它,只是提供信息):

var ConcernService = {

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

2
@Roylee 你可以将它注入到与 $rootScope 相同的函数中。例如:yourModuleName.run(function($rootScope, $state) { /* ... */ }); - Nate Abele
使用$stateChangeError似乎是合理的选择。但是如何知道错误代码呢? - Eugene Gluhotorenko
这取决于您的应用程序来决定。您可以自省其他参数并找出您想要转换到哪种错误状态。 - Nate Abele
这种情况不是500错误更合适吗?当某个Promise无法解析时,会触发stateChangeError,很可能是连接断开或服务器停止响应。 - XelharK
2
@XelharK 这取决于你的使用情况。也许用户跟随链接提取了一个参数并注入了 API 调用,该调用返回 404。在这种情况下,“未找到”错误完全适合显示(但是它有点无关紧要,因为 HTTP 错误代码/消息与 SPAs 完全无关)。 - Nate Abele
显示剩余4条评论

8
我区分了两种404状态: 服务端:
  • 根据服务器响应的HTTP代码404显示404页面
  • 重要的是定义没有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在这里解释了


1
你应该中止当前转换 $state.transition.abort(). 否则,你会看到 Transition Rejection The transition has been superseded by a different transition - sad comrade

3
你也可以尝试类似这样的方法,看看是否适合你。你可能需要根据自己的需求进行调整:
.state('otherwise', {
    abstract: true,
    templateUrl: 'views/404.html'
})
.state('otherwise.404', {
    url: '*path',
    templateUrl: 'views/404.html'
})

3
为什么你需要那个抽象路由呢?你可以用一个状态完成这个任务。 - Betty St
没有使用抽象路由对我也起作用了。我只是使用了.state('notFound' { url: '*path', templateUrl: 'views/404.html'}) - rjmunro

2
$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”。 - Darwin Tech
抱歉造成困惑,我只是举例子而已,让我更新一下代码。 - Alejandro Figueroa

1
我成功地处理了404错误,而不使用$urlRoutProvider,因为我只是通过测试$state.transistion来使用状态:
angular.module("app", []).run(["$state", "$rootScope", function($state, $rootScope) => {
    $rootScope.$on("$locationChangeSuccess", function() {
        if (!$state.transition) {
            $state.go("404");
        }
    });
}]);

0

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

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

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

如果您想有意引发404错误,请使用状态或URL。我们已经创建了一个单独的控制器,以便您执行任何操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接