I'd like to implement authentication on a single page web app with Angular.js. The official Angular documentation recommends the using of interceptors:
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
return {
// ...
'responseError': function(rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
}
};
});
The problem is when the server sends 401 error, the browser immediately stops with "Unauthorized" message, or with login pop-up window (when authentication HTTP header is sent by the server), but Angular can't capture with it's interceptor the HTTP error to handle, as recommended. Am I misunderstanding something? I tried more examples found on web (this, this and this for example), but none of them worked.
For AngularJS >1.3 use $httpProvider.interceptors.push('myHttpInterceptor');
.service('authInterceptor', function($q) {
var service = this;
service.responseError = function(response) {
if (response.status == 401){
window.location = "/login";
}
return $q.reject(response);
};
})
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}])
in app config block:
var interceptor = ['$rootScope', '$q', "Base64", function(scope, $q, Base64) {
function success(response) {
return response;
}
function error(response) {
var status = response.status;
if (status == 401) {
//AuthFactory.clearUser();
window.location = "/account/login?redirectUrl=" + Base64.encode(document.URL);
return;
}
// otherwise
return $q.reject(response);
}
return function(promise) {
return promise.then(success, error);
}
}];
I don't know why, but response with 401 error goes into success function.
'responseError': function(rejection)
{
// do something on error
if (rejection.status == 401)
{
$rootScope.signOut();
}
return $q.reject(rejection);
},
'response': function (response) {
// do something on error
if (response.status == 401) {
$rootScope.signOut();
};
return response || $q.when(response);
}
AngularJS interceptors only work for calls made with the $http service; if you navigate to a page that returns a 401, AngularJS never even runs.
Related
I want to intercepts only remote server calls.
I tried implementing Angular http interceptor but even it is intercepting local template call.
I got every request on console and check request made in Network Tab. It is differ in numbers.
I want reset session timeout on server call
$httpProvider.interceptors.push(function($rootScope) {
return {
'request': function(config) {
return config;
},
'response': function(response) {
return response;
},
'responseError': function(rejection) {
if (rejection.status === 401) {
location.reload();
}
return $q.reject(rejection);
}
};
});
Able to resolve it using $templateCache
Ref - Angular HTTP interceptor executed for embedded ng-templates
Below is the code if someone needed
$httpProvider.interceptors.push(function ($q, $rootScope,$templateCache) {
return {
'request': function(config) {
if( $templateCache.get(config.url) === undefined ){
console.log("Interceptor --> "+ config.url + " -" + $templateCache);
$rootScope.Idle.watch();
console.log(new Date());
}
return config;
},
'response': function (response) {
//Will only be called for HTTP up to 300
console.log(response);
return response;
},
'responseError': function (rejection) {
if(rejection.status === 401) {
location.reload();
}
return $q.reject(rejection);
}
};
});
I am very new to the angularjs, basically i want to check all $http request with angularjs interceptor and if the response data match 401 then redirect to login page
Any help appreciated
You can find more details on interceptors here.
In short, you can put following code in config section of your main module.
$httpProvider.interceptors.push(function($q, dependency1, dependency2) {
return {
response: function(response){
return promise.then(
function success(response) {
return response;
},
function error(response) {
if(response.status === 401){
//your redirection code goes here
return $q.reject(response);
}
else{
return $q.reject(response);
}
});
}
}
});
My question is what is the best way to handle errors from http REST calls. Should I use interceptors or decorators? My rest functions look something like this:
queryFunction : function (config) {
var defer = $q.defer();
var config = {};
$http.get(someUrl, config) //or http.put, delete
.then(function (response) {
defer.resolve(response.data);
})
.catch(function (ex) {
defer.reject(ex);
});
return defer.promise;
},
How will the simplest interceptor look?
Here's the code for generic $http ErrorInterceptor:
app.factory('ErrorInterceptor', ['$q', function($q) {
return {
responseError: function(rejection) {
// An error message is shown for all kind of server errors
if (rejection.status == -1) {
//alert('Backend is not working');
//use rejection.data variable
}
return $q.reject(rejection);
}
};
}])
Then it can be included into app config
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('ErrorInterceptor');
})
ExpressJS is sending the following response...
res.send('ItemUploaded');
I'm trying to get AngularJS to see this response via an Interceptor and perform a redirect. Does anyone have sample code where Angular catches a server response (such as my "ItemUploaded") and performs a redirect to a partial (via $location)?
This works fine. I have used it in my application.
var interceptor = function ($q, $location) {
return {
request: function (config) {//req
console.log(config);
return config;
},
response: function (result) {//res
console.log('Repos:');
console.log(result.status);
return result;
},
responseError: function (rejection) {//error
console.log('Failed with', rejection.status, 'status');
if (rejection.status == 403) {
$location.url('/dashboard');
}
return $q.reject(rejection);
}
}
};
module.config(function ($httpProvider) {
$httpProvider.interceptors.push(interceptor);
});
Here is the factory for the interceptor:
.factory('InterceptorService',['$q', '$location', function( $q, $location, $http){
var InterceptorServiceFactory = {};
var _request = function(config){
//success logic here
return config;
}
var _responseError = function(rejection) {
//error here. for example server respond with 401
return $q.reject(rejection);
}
InterceptorServiceFactory.request = _request;
InterceptorServiceFactory.responseError = _responseError;
return InterceptorServiceFactory;
}]);
then register the interceptor:
.config(["$httpProvider", function ($httpProvider) {
$httpProvider.interceptors.push('InterceptorService');
}]);
Every request coming will be passed here.
You can implement a interceptor factory which will redirect if it gets a matching result.
angular
.module('app')
.factory("httpinterceptor", ["$location",
function(location) {
return {
'response': function(response) {
if (response.data === "ItemUploaded") {
location.path("/ItemUploaded")
}
}
}
}
]);
I'm trying to configure the $http service of Angular, to redirect to an URL when the status code is 403.
No problems so far but the URL to redirect to is coming from the server, through a service which is using $http (obiously).
Here's a piece of code:
angular
.module('app')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(['$q', 'URLs',
function($q, Redirect) {
return {
request: function(config) {
return config || $q.when(config);
},
responseError: function(response) {
if(response.status === 403) {
// redirect to URLs.login
}
return $q.reject(response);
}
};
}
]);
}])
.factory('URLs', ['$http', function($http) {
var URLs;
$http.get('/urls').then(function(response) {
URLs = response.data;
});
return URLs;
}]);
This code is creating a circular dependency (error) in Angular.
Is there a way that I can do this, having dynamic URLs that are coming from a server and based on this to redirect the user to one of them when the response.status is 403?
Use $injector service to lazily load the URLs service:
angular
.module('app')
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(['$q', '$injector',
function($q, $injector) {
return {
request: function(config) {
return config || $q.when(config);
},
responseError: function(response) {
var Redirect = $injector.get('URLs');
if(response.status === 403) {
// redirect to URLs.login
}
return $q.reject(response);
}
};
}
]);
}])
You can also break this circular dependency in the URLs service by injecting the $injector there.