Angular $httpProvider Interceptor and $resource - javascript

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/

Related

How to throw error from 'reponse' function of $httpProvider interceptor

I am making a http interceptor in angular and I want to make throw error from response of $httpProvider interceptor.
As per the documentation:
response: interceptors get called with http response object. The function is free to modify the response object or create a new one. The function needs to return the response object directly, or as a promise containing the response or a new response object.
responseError: interceptor gets called when a previous interceptor
threw an error or resolved with a rejection.
I want to do the bold part in above quote so that a response with status 200 (I've a condition there) is routed to responseError where I will handle the error.
Not returning a response throws following error:
Cannot read property 'data' of undefined
I do not want to return the response but want to pass it to next handler i.e responseError.
How can I do that?
I hope I made it clear.
Thanks.
Update (Code Below):
app.config(['$httpProvider', function($httpProvider) {
interceptor.$inject = ['$q', '$rootScope'];
$httpProvider.interceptors.push(interceptor);
function interceptor($q, $rootScope) {
return {
response: response,
responseError: responseError
};
function response(response) {
if (response.data.rs == "F") {
// I want to route it responseError -->
} else {
return response;
}
}
function responseError(response) {
// I want to handle that error here
}
}
}]);
Use:
return $q.reject(response);
Also make sure you return: (Read about it here)
return response || $q.when(response);
instead of:
return response;

Angularjs - Anonymous template load cause response error in interceptor

Would like to check, I am using AngularJS 1.4.4 with AngularUI. So recently I have upgraded my site to use JWT tokens. The JWT tokens are being sent via headers in http request. So I've also added an interceptor to intercept all requests Angular made to the server like this
request: function(config){
config.headers = config.headers || {};
if ($localStorage.jwtToken) {
config.headers.Authorization = 'Bearer ' + $localStorage.jwtToken;
}
return config;
},
response: function(response) {
if(response.headers('New-Jwt-Token')){
console.log(response.headers('New-Jwt-Token'));
}
},
responseError: function (response) {
// handle the case where the user is not authenticated
if (response.status === 401) {
if(response.data.error === 'token_ttl_expired'){
if(response.data.new_jwt_token){
$localStorage['jwtToken'] = response.data.new_jwt_token;
console.log('jwt updated');
}
}
}
return $q.reject(response);
}
What I have noticed is while angular made the requests there is also many anonymous template requests being made to routes that dont exist in my website which causes then entire program to stop working.
How should i remove / prevent / delete these unnecessary templates from loading?
Update: If found out this is actually cause by the AngularUI bootstrap.
How should i prevent this from being intercepted by the interceptor?
Your error is more than likely caused by no response being returning in your response interceptor. So it should be:
response: function(response) {
if(response.headers('New-Jwt-Token')){
console.log(response.headers('New-Jwt-Token'));
}
return response;
},
The request interceptor will intercept all requests AFAIK. Note that with ui-bootstrap, the templates are cached in the $templateCache so no actual GET is actually sent to your server.
This is completely unnecessary but what you can do in your request interceptor is to do nothing if found in the $templateCache.
request: function(config){
if (config.url && $templateCache.get(config.url)) {
// Don't do anything
return config;
}
config.headers = config.headers || {};
if ($localStorage.jwtToken) {
config.headers.Authorization = 'Bearer ' + $localStorage.jwtToken;
}
return config;
},
Again, this is not necessary and doesn't achieve much but I put it here incase you have other processing logic in the request interceptor.

AngularJS $http redirect on status code

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);
}
};
}
]);
}
]);

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