Why angular $resources not have a request and request error interceptor?
Theres any way to do that?
Doc content:
interceptor - {Object=} - The interceptor object has two optional methods - response and responseError. Both response and responseError interceptors get called with http response object. See $http interceptors.
You can implement your own interceptors as follows.
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('myInterceptor');
});
app.factory('myInterceptor', ['$q', function ($q) {
return {
request: function (config) {
config.headers = config.headers || {};
// insert code to populate your request header for instance
return config;
},
response: function (response) {
if (response.status === 403 || response.status === 401) {
// insert code to redirect to custom unauthorized page
}
return response || $q.when(response);
}
};
}]);
I hope this will help you out.
Related
I have an $http service that make an API call and I have a transformResponse and error interceptor both attached to every call. In case of errors I can see that transform response gets called first, then followed by an interceptor. I do not want the transformation method to be called for error responses, I want it to skip right to the interceptor. How can I achieve that?
I know that I can put if (response.status != 200) into every transformation method, but I have a lot of these methods and I do not want to do that in each of them.
You probably need to go for Interceptors to play with request response in general.
myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
},
response: function (response) {
if (response.status === 401) {
// handle the case where the user is not authenticated
}
return response || $q.when(response);
}
};
});
myApp.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
Perhaps it will also be useful
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.transformResponse.unshift(
function (data, headers) {
/* some code*/
return data;
});
}])
I am implementing token based authentication with AngularJS. The token is created on server and returned to client. After authentication, the token will be added to header of every rest call. I created a authInterceptor:
ristoreApp.factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.localStorage.getItem("access_token")) {
config.headers.Authorization = 'Bearer ' + $window.localStorage.getItem("access_token");
}
return config;
},
response: function (response) {
if (response.status === 401) {
// handle the case where the user is not authenticated
}
return response || $q.when(response);
}
};
});
Then injected it in my config.js as follows:
ristoreApp
.config(function ($httpProvider, authInterceptor, $routeProvider) {
$httpProvider.interceptors.push('authInterceptor');
$routeProvider
.......
})
However I got the following error:
Failed to instantiate module ristoreApp due to: Unknown provider: authInterceptor
What is wrong with my way to inject the interceptor?
this Failed to Instantiate module happens when you have NOT defined
ristoreApp
in your Routing file.
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 have make a POST request to an API and they have basic authentication, how can I tell angular $http POST service to pass my credential while making the post requestion?
You can add auth interceptor as follows
angular.module('interceptors.authInterceptor',[])
.factory('authInterceptor', ['$q', function ( $q) {
return {
request: function (config) {
config.headers = config.headers || {};
config.headers['Authorization'] = 'Bearer ' + YOUR_AUTH_TOKEN;
return config;
},
response: function (response) {
return response || $q.when(response);
},
responseError: function(rejection) {
}
};
}])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}]);
I have a current 401 check that I'm running with $location which is working fine. However I'd like to swap it over to $state and use ui-router instead. When I do so i get an error code as:
Circular dependency found: $http <- $templateFactory <- $view <- $state <- authHttpResponseInterceptor <- $http <- $compile
My currently code looks fine as I check certain paths and allow no logged in users to view them:
/* Look for 401 auth errors and then redirect */
.factory('authHttpResponseInterceptor',['$q','$location', function($q,$location) {
return {
response: function(response){
if (response.status === 401) {
}
return response || $q.when(response);
},
responseError: function(rejection) {
var reservedPaths = ['/','/login','/connect','/event'];
if (rejection.status === 401 && _.contains(reservedPaths,$location.path().trim())) {
$location.path('/welcome');
}
return $q.reject(rejection);
}
};
}])
.config(['$httpProvider',function($httpProvider) {
//Http Intercpetor to check auth failures for xhr requests
$httpProvider.interceptors.push('authHttpResponseInterceptor');
}]);
The code I added is as follows.:
/* Look for 401 auth errors and then redirect */
.factory('authHttpResponseInterceptor',['$q','$location', **'$state',** function($q,$location, **$state**) {
return {
response: function(response){
if (response.status === 401) {
}
return response || $q.when(response);
},
responseError: function(rejection) {
var reservedPaths = ['/','/mycube','/connect','/event'];
if (rejection.status === 401 && _.contains(reservedPaths,$location.path().trim())) {
**$state.go('home');**
}
return $q.reject(rejection);
}
};
}])
.config(['$httpProvider',function($httpProvider) {
//Http Intercpetor to check auth failures for xhr requests
$httpProvider.interceptors.push('authHttpResponseInterceptor');
}]);
Why would adding state cause this issue when it works fine with location?
It appears that $state service is resulting in a circular dependency with the $http service. This may be caused by the fact that the templateFactory (see https://github.com/angular-ui/ui-router/blob/master/src/templateFactory.js) is being injected with the $http service in addition to the interceptor itself being composed with the $http service.
To get around this circular dependency issue, you can use the $injector service to wire up the $state service to your interceptor. See the revised code:
/* Look for 401 auth errors and then redirect */
module.factory('authHttpResponseInterceptor', ['$q','$location', '$injector', function($q, $location, $injector) {
return {
response: function(response){
if (response.status === 401) {
}
return response || $q.when(response);
},
responseError: function(rejection) {
var reservedPaths = ['/', '/mycube', '/connect', '/event'];
if (rejection.status === 401 && _.contains(reservedPaths, $location.path().trim())) {
var stateService = $injector.get('$state');
stateService.go('home');
}
return $q.reject(rejection);
}
};
}]);
You can learn more about the $injector service here: https://docs.angularjs.org/api/auto/service/$injector
IMPORTANT
I would recommend using the state change events (see https://github.com/angular-ui/ui-router/wiki#state-change-events) to watch for errors using $stateChangeError and inspecting the error returned from the 401.
Here is the simplest solution I did and it worked. Inside the factory write:
var $http = $injector.get("$http");
and then use $http as you normally would.
NOTE: If you don't have $injector available in your factory simply inject it as follow
.factory('authHttpResponseInterceptor',['$q','$location','$injector', function($q,$location,$injector) {
}])