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);
}
});
}
}
});
Related
All of our content pages have a particular header, X-Foo. When the content of the ng-view changes, we want to display the new page's X-Foo header in a different element. How can we get this value whenever the content changes?
EDIT: Since this was apparently unclear, the header is expected in the response, not the request.
You can use a httpInterceptor for this. HTTP interceptors are a great way to define behavior in a single place for how a request or response is handled for all HTTP calls using the $http service
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
}).factory('httpInterceptor', function (liveInterviewConfiguration) {
return {
request : function (request) {
console.info("Your request headers are");
console.info(request.headers);
return request;
},
requestError : function (error) {
return error;
},
response : function (response) {
return response;
},
responseError : function (error) {
return error;
}
};
});
Can you access the headers in the controller with $http? I've nothing that has changing headers readily available to test this with.
controller('SampleCtrl', function($http, $scope) {
// Add headers from $http
$scope.http = $http.defaults.headers.common;
});
Alternatively, if that does not work, you may want to look at using http interceptors.
.config(function($routeProvider, $locationProvider, $httpProvider) {
$httpProvider.interceptors.push(function($q) {
return {
'response': function(response) {
// do something on success
console.log(response);
return response;
}
};
});
}
Can you tell me what is the correct way to redirect to another page if $http.post returns a specific error code.
Just to add context, I want to redirect to another page if the user is not logged in or authorized to use the API.
function getData(filter) {
var deferred = $q.defer();
var data = JSON.stringify(filter);
$http.post('/myapp/api/getData', data)
.success(function (data, status, headers, config) {
deferred.resolve(data);
})
.error(function (error) {
deferred.reject(error);
});
return deferred.promise;
}
You could do a redirect to the page using $window.location.href, based on the error condition you have.
var app = angular.module("sampleApp", []);
app.controller("sampleController", [
"$scope",
'$window',
'sampleService',
function($scope, $window, sampleService) {
sampleService.getData().then(function(result) {}, function(error) {
if (error.statusCode === 400) {
alert("Error");
$window.location.href = "http://stackoverflow.com"
}
});
}
]);
app.service("sampleService", function() {
this.getData = function() {
var promise = new Promise(function(resolve, reject) {
setTimeout(function() {
reject({
statusCode: 400
});
}, 1000);
});
return promise;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-App="sampleApp">
<div ng-controller="sampleController">
</div>
</div>
The best way to catch global AuthenticationErrorin angular is with interceptor.
This way you can monitor all request that are sent from angular and check for AuthenticationError.
$provide.factory('AuthErrorInterceptor', function($q, $location) {
return {
'responseError': function(rejection) {
//check for auth error
$location.path('/login');
return $q.reject(rejection);
}
};
});
Example :
$http.post('/myapp/api/getData', data)
.then(function (data) {
if(data.ErrorCode==1)
{
$window.location.href="controllerName/actionName";
}
})
Use a interceptor service in order to centralize all of your rejection request in the same service.
module.config(['$httpProvider', ($httpProvider: ng.IHttpProvider) => {
$httpProvider.interceptors.push('errorService');
}]);
module.factory('errorService', ['$location', function($location) {
var errorService = {
responseError: function(rejection) {
if (rejection === '401') {
$location.path('/login');
}
}
};
return errorService;
}]);
The $http.post is misguiding.
So far the best answer is #Kliment's. Interceptors are the best way to manage what comes before and after http requests.
However, if your end goal is to prevent access to a page, you have to at least use a routing plugin (ngRoute, ui-router) because with the promise idea there will always be a delay between the http request and the response.
Depending on server response time you'll still see the page display for about a second or so.
With ui-router you simply configure a resolve method for each state you want to protect. It could look like this:
.state('protected',
{
url : '/protected_page',
templateUrl : 'secret.html',
resolve: {
loggedin: loggedin
}
})
loggedin refers to a function you define that contains your $http.post call (or better yet a service)
function loggedin($timeout, $q, $location, loginService) {
loginService.then(function(data) {
if(data.status == 401) {
//$timeout(function() { $location.path('/login'); });
return $q.reject();
} else {
return $q.when();
}
});
}
Here this particular service returns a 401 status but you can return anything.
The state will not be resolved (and the page not displayed) until it's accepted or rejected.
You can redirect directly from there if you want, although it's not very elegant.
ui-router gives you another option with default redirection:
if (tokenIsValid())
$urlRouterProvider.otherwise("/home");
else
$urlRouterProvider.otherwise("/login");
With otherwise you tell ui-router to go to certain urls if no state exists for a particular request or if a resolve has been rejected.
On another subject, your http request is badly written.
.success and .error are deprecated and you don't need to create a promise ($q) over an $http request that itself already returns a promise.
You have a good example in the documentation linked above.
You can redirect to page on unauthorized access of a user based on the status code which you can return from your API call.
$http({
method: "POST",
url: 'Api/login',
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
}).success(function (data,status) {
if(status==200){
alert('Successfully logged in');
$location.path('/dashboard'); //You can use this if you are defined your states.
}
}).error(function (data,status) {
if(status==403||status==403){ //Based on what error code you are returning from API
$location.path('/login');// if states are defined else
$window.location.href = "https://www.google.com";
}
});
First of all Nice Question , In this scenario You Can use $location , $state If it is external url You can use $window.location.href ... I would recommend $location and it is the best way ...
Please See the link for further Using $window or $location to Redirect in AngularJS
function getData(filter) {
var deferred = $q.defer();
var data = JSON.stringify(filter);
$http.post('/myapp/api/getData', data)
.success(function (data, status, headers, config) {
deferred.resolve(data);
if(data.errorcode==9999) // Define Your Error Code in Server
{
$location.path('/login'); // You Can Set Your Own Router
} })
.error(function (error) {
$location.path('/login'); // You Can Set Your Own Router
deferred.reject(error);
});
return deferred.promise;
}
Preferably use $location or $state ...
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');
})
I want to capture all request going out from my one page application like clicking on different tab or any hyperlink.
I have written an interceptor and want to put a ajax call for all request.
.factory('httpRequestInterceptor', function($q,$http){
return {
request: function($http,config){
window.alert(config.url);
var dummyValue = $http.get("url");
return config;
}
}
})
.config(function($httpProvider) {
$httpProvider.interceptors.push('httpRequestInterceptor');
});
I think you are in search of http logger kind of factory. You can use this one
.config(function ($provide, $httpProvider) {
// Intercept http calls.
$provide.factory('MyHttpInterceptor', function ($q) {
return {
// On request success
request: function (config) {
console.log(config); // Contains the data about the request before it is sent.
// Return the config or wrap it in a promise if blank.
return config || $q.when(config);
},
// On request failure
requestError: function (rejection) {
console.log(rejection); // Contains the data about the error on the request.
// Return the promise rejection.
return $q.reject(rejection);
},
// On response success
response: function (response) {
console.log(response); // Contains the data from the response.
// Return the response or promise.
return response || $q.when(response);
},
// On response failture
responseError: function (rejection) {
console.log(rejection); // Contains the data about the error.
// Return the promise rejection.
return $q.reject(rejection);
}
};
});
// Add the interceptor to the $httpProvider.
$httpProvider.interceptors.push('MyHttpInterceptor');
});
I tested, it works for routeProvider navigation as well. For more information please check this blog https://djds4rce.wordpress.com/2013/08/13/understanding-angular-http-interceptors/
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.