AngularJS $http redirect on status code - javascript

I have a angular application with many $http request and i want redirect the users on the login page if the server session expires (get 401). Does anyone know a solution witch works for all $http without adding .error() on every $http?

It would be better if you could use an http interceptor to redirect all detected 401 errors.
// add an http interceptor via app.config
app.config(function($$httpProvider) {
$httpProvider.interceptors.push('my401Detector');
});
// interceptor logic.
app.factory('my401Detector', function($location, $q) {
return {
responseError: function(response) {
if(response.status === 401) {
$location.path('/login');
return $q.reject(response);
}
else {
return $q.reject(response);
}
}
};
});

You can use Interceptors to achieve this. From Mean.js source code
angular.module('users').config(['$httpProvider',
function($httpProvider) {
// Set the httpProvider "not authorized" interceptor
$httpProvider.interceptors.push(['$q', '$location', 'Authentication',
function($q, $location, Authentication) {
return {
responseError: function(rejection) {
switch (rejection.status) {
case 401:
// Deauthenticate the global user
Authentication.user = null;
// Redirect to signin page
$location.path('signin');
break;
case 403:
// Add unauthorized behaviour
break;
}
return $q.reject(rejection);
}
};
}
]);
}
]);

Related

Angular $httpProvider Interceptor and $resource

I have a simple Interceptor in angular that intercepts requests and adds a authorization header. It also intercepts a response error of 401 to know if the request failed because of authorization.
Unfortunately it seems to mess with $resource, because my $resource calls ALWAYS return the success callback and never an error (be it 400 or 500 whatever).
It's definitly the interceptor, because if I remove it, the $resource calls return with the correct callback.
Any ideas on how to fix this behavior?
Here's the interceptors request:
function request(config) {
var token = 'whatever-my-token-is';
if (token) {
config.headers.authorization = token;
}
return config;
}
And the responseError:
function responseError(response) {
if (response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return response;
}
Any help appreciated
I think you need to use a promise to return the error.
adding $q to your Interceptor factory.
like so
$provide.factory('MyHttpInterceptor', function ($q){
...
})
and then have the responseError()
function responseError(response) {
if (response.status === 401) {
$rootScope.$broadcast('unauthorized');
}
return $q.reject(response);
}
this link might help also https://djds4rce.wordpress.com/2013/08/13/understanding-angular-http-interceptors/

AngularJS routeprovider won't do anything

I'm trying to check before every page load if his session is active, if not, redirect to the login page.
This is my App.js
var app = angular.module('Test', ['ngRoute']);
app.config(function($routeProvider){
$routeProvider
.otherwise({
resolve:
{
"checkUserSession": function($q,$http,$window)
{
console.log('start of the def')
var deffered = $q.defer();
$http.get('/general/php/getCurrentUser.php')
.then(function(result)
{
if(!result)
{
deffered.reject();
$window.location.href = "/";
}
else
{
deffered.resolve();
}
});
$window.location.href = "/";
return deffered.promise;
}
}
})
});
And it won't execute the console.log, the $http.get() or any of the redirects.
It doesn't matter if the promise is resolved or rejected, it looks likes the "checkUserSession" won't ever execute;
Every page includes the angular-route.js script.
Use an interceptor.
In my case I check for the authentication token in local storage but you could use your session logic here.
Start with angular.module(...).config -
.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {
$httpProvider.interceptors.push('BearerAuthInterceptor');
...
Then use a service as following:
.factory('BearerAuthInterceptor', function ($q, $injector, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
var tk = $window.localStorage.getItem('token');
if (tk) {
config.headers.Authorization = 'Bearer ' + tk;
}
return config || $q.when(config);
},
response: function (response) {
return response || $q.when(response);
},
responseError: function (rejection) {
if (rejection.status === 401) {
// Redirect to login ui-route
$injector.get('$state').go('login');
}
return $q.reject(rejection);
}
};
})
Some good examples here: http://www.webdeveasy.com/interceptors-in-angularjs-and-useful-examples/

How to detect all http GET fails?

In my application I have a grid which fetches data via HTTP promises. At the moment I can detect errorCallbacks - as below:
myDataPromise.then(function () {
//do stuff
}, function errorCallback(response) {
if (response.statusText === "Not Found") {
//do stuff
}else if(response.statusText === "Internal Server Error"){
//do stuff
}
but say for an SSL error, where chrome fires back "ERR::CONNECTION REFUSED" I cannot pick up on this by reading the string as I can with 404's etc. Really what I want is to display a simple image/text stating that there has been an error in retrieving one's data no matter what it is. So if a http GET fails at all - the user knows. This seems to me like a fairly typical spec but I can't find much online regarding it.
You have to create a interceptor
// register the interceptor as a service
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
return {
// optional method
'request': function(config) {
// do something on success
return config;
},
// optional method
'requestError': function(rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
},
// optional method
'response': function(response) {
// do something on success
return response;
},
// optional method
'responseError': function(rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('myHttpInterceptor');
// alternatively, register the interceptor via an anonymous factory
$httpProvider.interceptors.push(function($q, dependency1, dependency2) {
return {
'request': function(config) {
// same as above
},
'response': function(response) {
// same as above
}
};
});
The interceptor intercepts all the $http traffic. Even when you are loading templates.

How to intercept all http requests using AngularJS?

My Question is a bigger and broader version of this question. I want to intercept all http requests issued inside an AngularJS function. Later I need to alter the request URL and than pass it to the server..
How can I do that ? So far I have used $httpProvider and $q to create a interceptor but I am only able to intercept only $http requests not all the requests i.e. if someone clicks on any href link on my page etc. My interceptor code is :-
// register the interceptor as a service
myModule.factory('myHttpInterceptor', function ($q) {
return {
// optional method
'request': function (config) {
// do something on success
console.log("request success");
return config;
},
// optional method
'requestError': function (rejection) {
// do something on error
console.log("Request Error");
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
},
// optional method
'response': function (response) {
// do something on success
console.log("Response received");
return response;
},
// optional method
'responseError': function (rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
}
};
});
myModule.factory('myInterceptor', ['$log', function ($log) {
$log.debug('$log is here to show you that this is a regular factory with injection');
var myInterceptor = {
};
return myInterceptor;
}]);
myModule.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('myHttpInterceptor');
}]);
Intercepting navigation to other pages is different from intercepting http requests. Maybe what you want is to intercept $location changes.
Have a read through this. You can do it but it depends on where the location changes are to.
http://uiadventures.wordpress.com/2013/09/06/routechange-angularjs/

Trying to fire a ui-modal on a 401 server response

I'm trying to fire a login modal anytime the server responds with a 401 status code. Based on this guide https://medium.com/opinionated-angularjs/7bbf0346acec I've created a status code interceptor like this.
// intercept http status codes
app.config(function ($httpProvider) {
$httpProvider.interceptors.push(['$injector', function ($injector) {
return $injector.get('AuthInterceptor');
}]);
});
app.factory('AuthInterceptor', function ($rootScope, $q) {
return {
responseError: function (res) {
if (res.status === 401) {
console.log('AuthInterceptor says you are not authorized');
}
if (res.status === 404) {
console.log('AuthInterceptor says this page is not found');
}
return $q.reject(res);
}
};
});
When I try to inject my AuthInterceptor factory with $modal I get a circular dependency error. What is a good practice for triggering a $modal from something like this? The guide that I linked used this AuthInterceptor factory to broadcast 'Auth_events', which were simply constant strings. They didn't show any use of these auth_events beyond broadcasting them so I don't understand how they're suppose to work. In addition to my main question can anyone clarify what these auth events do?
You are getting a circular dependency error since the $modal service has dependency on $http. This is a common problem with $http interceptors that got dependency on $http themselves. Fortunately the remedy is simple: you need to inject $injector into your interceptor and retrieve $model from the injector like so:
app.factory('AuthInterceptor', function ($rootScope, $q, $injector) {
return {
responseError: function (res) {
var $modal = $injector.get('$modal');
if (res.status === 401) {
//you can use $modal here...
console.log('AuthInterceptor says you are not authorized');
}
if (res.status === 404) {
console.log('AuthInterceptor says this page is not found');
}
return $q.reject(res);
}
};
});

Categories