可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have an app with a service which wraps my API calls:
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;
},
and I'm using UI-Router to transition between states:
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: {
...
}
});
I'm moving from using the normal AngularJS router and I'm having difficulty understanding how to implement 404s. I can see the ConcernService
throwing the console.log
status as rejected, but how do I catch this in the state router?
回答1:
The otherwise()
rule is only invoked when no other route matches. What you really want is to intercept the $stateChangeError
event, which is what gets fired when something goes wrong in a state transition (for example, a resolve failing). You can read more about that in the state change event docs.
The simplest implementation for what you're trying to do would be something like this:
$rootScope.$on('$stateChangeError', function(event) {
$state.go('404');
});
Also, since $http
itself is built on promises (which resolve
resolves), your ConcernService
method can be simplified down to a one-liner (I realize you expanded it for debugging purposes, but you could have just as easily chained it, just FYI):
var ConcernService = {
get: function (items_url, objId) {
return $http.get(api_url + items_url + objId);
}
}
回答2:
I differ between two 404 states:
Server:
- show 404 page depending on server response HTTP Code 404
- important to define no URL, so that user stays on URL where the error happened
Client:
- URL is not found by angular ui router (none of defined URLs)
Code for Angular UI-Router state:
$stateProvider
.state('404server', {
templateUrl: '/views/layouts/404.html'
})
.state('404client', {
url: '*path',
templateUrl: '/views/layouts/404.html'
});
Code in $httpProvider
interceptor:
if(response.status === 404) {
$injector.get('$state').go('404server');
}
And why I used $injector
instead of $state
is explained here.
回答3:
You can also try something like this and see if it works for you. You may need to adjust to your needs:
.state('otherwise', {
abstract: true,
templateUrl: 'views/404.html'
})
.state('otherwise.404', {
url: '*path',
templateUrl: 'views/404.html'
})
回答4:
The $urlRouterProvider only works like a $watch to $location and if the actual URL matches one of the rules defined in the .config() function then it will redirect to the specified route.
Here's what I recommend, define "/404/" as a state:
$stateProvider.state('404', {
url:'/404/',
views:{
...
}
});
And inside the reject() function move to 404 state
if(status == '404'){
$state.transitionTo('404');
}
You will have to add ui-router as dependency of the project module and use the $state provider in your controller in order to be able to use $state.transitionTo()
Here's some info: https://github.com/angular-ui/ui-router/wiki/Quick-Reference#statetransitiontoto-toparams--options
回答5:
I managed to handle 404 without using $urlRoutProvider
since I'm only using states by testing $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"
})
Will handle your page not found problem.
If you want to raise 404 found purposefully use the state or url. We have created a separate controller just if you want to perform any operations.