How to use angularJS interceptor to only intercept specific http requests? - angularjs

I know how to intercept ALL requests, but I only want to intercept requests from my resources.
Does anyone know how to do this?
services.config(['$httpProvider',function($httpProvider) {
$httpProvider.interceptors.push('myHttpInterceptor');
}]);
services.factory("userPurchased", function ($resource) {
return $resource("/api/user/purchases/:action/:item",
{},
{
'list': {method: 'GET', params: {action: 'list'}, isArray: false},
'save': {method: 'PUT', params: {item: '#item'}},
'remove': {method: 'DELETE', params: {item: '#item'}},
}
);
});
services.factory('myHttpInterceptor', function($q,$rootScope) {
// $rootScope.showSpinner = false;
return {
response: function(response) {
$rootScope.showSpinner = false;
// do something on success
console.log('success');
console.log('status', response.status);
//return response;
return response || $q.when(response);
},
responseError: function(response) {
// do something on error
$rootScope.showSpinner = true;
console.log('failure');
console.log('status', response.status)
//return response;
return $q.reject(response);
}
};
});

If you want to intercept only requests from specific resources, you can use optional interceptor property of $request action. Angular's documentation see here (Usage>actions)
JavaScript
angular.module('app', ['ngResource']).
factory('resourceInterceptor', function() {
return {
response: function(response) {
console.log('response intercepted: ', response);
}
}
}).
factory('resourceService', ['$resource', 'resourceInterceptor', function($resource, resourceInterceptor) {
return $resource(":name",
{},
{
'list': {method: 'GET', isArray: false, interceptor: resourceInterceptor}
}
);
}]).
run(['resourceService', '$http', function(resourceService, $http) {
resourceService.list({name: 'list.json'}); // <= intercepted
$http.get('list.json'); // <= not intercepted
}]);
Plunker: http://plnkr.co/edit/xjJH1rdJyB6vvpDACJOT?p=preview

The only way I know of doing this it to just filter out the requests you want in the response handler.
e.g.
...
response: function(response) {
if(response.config.url.startsWith('/api/')) {
//Do your custom processing here
}
return response;
}
...
Polyfill for string.startsWith()
//Taken from http://stackoverflow.com/questions/646628/javascript-startswith
if (typeof(String.prototype.startsWith) === 'undefined') {
String.prototype.startsWith = function(str) {
return this.slice(0, str.length) === str;
};
}

My preferred way is to use an HTTP interceptor which replaces a "magic" Authorization header with the current OAuth token. The code below is OAuth specific, but remedying that is a simple exercise for the reader.
// Injects an HTTP interceptor that replaces a "Bearer" authorization header
// with the current Bearer token.
module.factory('oauthHttpInterceptor', function (OAuth) {
return {
request: function (config) {
if (config.headers.Authorization === 'Bearer') {
config.headers.Authorization = 'Bearer ' + btoa(OAuth.accessToken);
}
return config;
}
};
});
module.config(function ($httpProvider) {
$httpProvider.interceptors.push('oauthHttpInterceptor');
});

/**object single interceptor**/
function SingleCallInterceptor(callbacks){
this.receive=function(response) {
switch (response.status) {
case 200:
callbacks.success(apiResponse);
break;
default :
callbacks.error(response);
}
}
}
var successfn=function(response){ //i have my response}
var errorfn=function(response){ //i have my error}
var responseInterceptor=new SingleCallInterceptor({success:successfn,error:errorfn});
$http({
url: "www.itsdirtysolutioniknow.it,
method: "GET",
dataType: "JSONP",
}).then(responseInterceptor.receive,responseInterceptor.receive);

By default angular sends and receives application/json headers. You can get this on the HTTP response header like :
services.config(['$httpProvider',function($httpProvider) {
$httpProvider.interceptors.push('myHttpInterceptor');
}]);
services.factory("userPurchased", function ($resource) {
return $resource("/api/user/purchases/:action/:item",
{},
{
'list': {method: 'GET', params: {action: 'list'}, isArray: false},
'save': {method: 'PUT', params: {item: '#item'}},
'remove': {method: 'DELETE', params: {item: '#item'}},
}
);
});
services.factory('myHttpInterceptor', function($q,$rootScope) {
// $rootScope.showSpinner = false;
return {
response: function(response) {
// use this line to if you are receiving json, else use xml or any other type
var isJson = response.config.headers.Accept.indexOf('json')>-1;
$rootScope.showSpinner = false;
// do something on success
console.log('success');
console.log('status', response.status);
//return response;
return response || $q.when(response);
},
responseError: function(response) {
// use this line to if you are receiving json, else use xml or any other type
var isJson = response.config.headers.Accept.indexOf('json')>-1;
// do something on error
$rootScope.showSpinner = true;
console.log('failure');
console.log('status', response.status)
//return response;
return $q.reject(response);
}
};
});

I just came across an issue where googleapis also uses an Authorization header, and was throwing a 401 response because the JWT I use on my server wasn't valid for their server (obviously), and my code was set to automatically remove my token and redirect the person to the login page. (It wasn't written super well, since ANY 401 response would log my user out).
I just came up with this solution in my request method in the interceptor, which I think works pretty well:
.service('authInterceptor', ["$q", "$location", "tokenService", function($q, $location, tokenService){
this.request = function(config) {
// console.log($location.host());
var token = tokenService.getToken();
if(token && config.url.indexOf($location.host()) > -1) {
config.headers = config.headers || {};
config.headers.Authorization = "Bearer " + token
}
return config
}
this.responseError = function(response) {
// console.log(response.config.url)
if (response.status === 401) {
tokenService.removeToken();
$location.path('/login')
}
return $q.reject(response);
}
}])
The request method checks if I have a token in local storage AND if the request url is being made to the same host (which I get from $location.host()) as the one my page is being served up on. This works for localhost as well as whatever URL I end up deploying my site on.
I haven't done much testing with this, so if anyone finds a flaw in this please let me know :)

I know it is an old question but I wanted to provide a solution if you have pushed multiple $http Interceptors and want them to continue working, return your response so the Interceptor chain continues:
module.factory('resourceInterceptor', ['$q', function($q) {
return {
response: function(response) {
// do your conditional logic here
if (...) {
return $q.resolve(response);
}
},
responseError: function(response) {
// do your conditional logic here
if (...) {
return $q.reject(response);
}
}
};
}]);

Related

Angularjs interceptor: Interceptor in not work

Hi this below is my code from angularjs
The first part of the code shows exactly how I make the request to php which returns me data when there is code with an error when there is a problem.
When it returns me an error code, for example 401, the frontend explodes with an error and everything breaks.
As far as I understand, I have to use an interceptor so that I can catch the error number and not make an error.
I can't do this interception.
app.js
app.factory('httpRequester', function ($http, $route) {
var promise;
var myService = {
async: function (myData) {
//Create my obj for request
var req = {
method: myData.Method,
url: 'https://**********/' + url,
headers: {
'X-API-KEY': '**************',
'KEY': myData.Authentication.AccessToken
},
data: myData
};
promise = $http(req).then(function (response) {
if (response.data === 'permission denied') {
window.location.href = '#/';
} else {
return response;
}
});
return promise;
}
};
return myService;
});
//set interceptor in app.js
var interceptorApp = angular.module('interceptorApp', []);
interceptorApp.config(function($httpProvider) {
$httpProvider.interceptors.push('genericInterceptor');
});
Please help me with my problem, how to set interceptor work.
//Function for set error and success after request
var testInterceptor = function ($q)
{
return {
request: function (config)
{
//console.log('request started...');
},
requestError: function (rejection)
{
console.log(rejection);
// Contains the data about the error on the request and return the promise rejection.
return $q.reject(rejection);
},
response: function (result)
{
// console.log('data for ' + result.data.name + ' received');
//If some manipulation of result is required before assigning to scope.
result["testKey"] = 'testValue';
console.log('request completed');
return result;
},
responseError: function (response)
{
// console.log('response error started...');
//Check different response status and do the necessary actions 400, 401, 403,401, or 500 eror
return $q.reject(response);
}
}
}

angularjs $http always return -1 with response status 404

I found a strange question in angular $http.
My request code
$http({
method: 'GET',
url: 'http://localhost:8080/server/'
}).then(function (response) {
console.log(response.status);
},function(response){
console.log(response.status);
});
Before that, I set the request header
app.factory('myInterceptor', ['$q', function($q) {
return {
request: function(config) {
config.headers['Authorization'] = 'Basic *';
return config;
},
requestError: function(rejectReason) {
return $q.reject(rejectReason);
},
response: function(response) {
return $q.resolve(response);
},
responseError: function(response) {
console.log(response.status);
return $q.reject(response);
}
};
}])
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('myInterceptor');
}]);
This page does not exist,so it should return 404,but it returns -1.
If remove this lineconfig.headers['Authorization'] = 'Basic *';,it returns right 404.
Can anybody help meļ¼Œthis is my demo page http://plnkr.co/edit/GhghMNCPcITwXCINISW5?p=preview , thank you very much
There are something wrong with your URL over which you are making request.
One can tell by updating the http call backs as follow :
app.controller('MainCtrl', function($scope, $http) {
$scope.name = 'angular'
$http({
method: 'GET',
url: 'https://cloudzone.eicp.net:8155/server/'
}).success(function(response) {
console.log(response.status);
}).error(function(response) {
console.log(response.status);
});
});
You will see that the server is neither returning Success nor Error, it is just getting timeout.
Please check the server's availability.
Suggestion: Try some utility such as 'postman' in google chrome and see what results you are getting.

How to access the $http service request object in Angular JS?

I am making an http request using the $http service as follows :
$http({
url: "URL",
method: "POST",
data: payload,
headers :{
"Content-Type": "application/json",
"access_token": xyz
}
}).then(function (response) {
$log.debug("Response :",response);
}, function (error) {
$log.debug("error :",error);
});
I need to access the request object(along with the headers,etc.) that I sent over. Is it possible in code?
Use an interceptor. Here is a good article and an example from it.
module.factory('timestampMarker', [function() {
var timestampMarker = {
request: function(config) {
config.requestTimestamp = new Date().getTime();
return config;
},
response: function(response) {
response.config.responseTimestamp = new Date().getTime();
return response;
}
};
return timestampMarker;
}]);
module.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('timestampMarker');
}]);
Using an interceptor will give you the ability to read into or add headers to the request, etc. Hope it helps.
You can see the request properties like in the example:
$http.post('/service', params).success(
function(data, status, headers, config) {
//...
console.log('properties', config.method, config.headers['Content-Type'], config);
});
or if you want to see/change properties before/after request in more global way you can use interceptors:
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(['$q', function($q) {
return {
'request': function(config) {
// for example:
config.headers['Content-Type'] = 'application/x-www-form-urlencoded';
// same more logic ...
return config;
},
'response': function(response) {
// for example:
if (!response.data || !response.data.status) {
return $q.reject(response);
}
// same more logic ...
return response;
},
'responseError': function(rejection) {
// same more logic ...
}
};
}]);
}]);

How to do error handling when fetching data in angularjs service

This code fetches categories and give them to controller.
sampleApp.factory('SCService', function($http, $q) {
var SuperCategories = [];
var SCService = {};
SCService.GetSuperCategories = function() {
var req = {
method: 'POST',
url: SuperCategoryURL,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: "action=GET"
};
if ( SuperCategories.length == 0 ) {
return $http(req).then(function (response) {
SuperCategories = response.data;
return SuperCategories;
});
}else {
return $q.when(SuperCategories);
}
}
return SCService;
});
I think code is perfect until there is no error in http request.
My query is how to do error handling (try catch or something like that), in case if server have some issue or may be cgi-script have some issue and not able to server the request.
Angular promises use a method catch for that.
return $http(req).then(function (response) {
SuperCategories = response.data;
return SuperCategories;
}).catch(function(error) {
// Do what you want here
});
You should use also finally :
return $http(req).then(function (response) {
SuperCategories = response.data;
return SuperCategories;
}).catch(function(error) {
// Do what you want here
}).finally(function() {
// Always executed. Clean up variables, call a callback, etc...
});
Write like
return $http(req).then(function (response) {
//success callback
},
function(){
//Failure callback
});
Use callback methods from controller Like
Controller.js
service.GetSuperCategories(function (data) {console.log('success'},function (error){console.log('error'});
service.js
sampleApp.factory('SCService', function($http, $q) {
var SuperCategories = [];
var SCService = {};
SCService.GetSuperCategories = function(successMethod,errorMethod) {
var req = {
method: 'POST',
url: SuperCategoryURL,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: "action=GET"
};
return $http(req).then(successMethod(data),
errorMethod(error));
}
return SCService;
});
You can use the .success and .error methods of $http service, as below
$http(req).success(function(data, status, headers){
// success callback: Enters if status = 200
}).error(function(status, headers){
// error callback: enters otherwise
});

AngularJS withCredentials

I've been working on an AngularJS project which has to send AJAX calls to an restfull webservice. This webservice is on another domain so I had to enable cors on the server. I did this by setting these headers:
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Origin", "http://localhost:8000");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Credentials", "true");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
I'm able to send AJAX requests from AngularJS to the backend but I'm facing a problem when I try to get an attribute of a session. I believe this is because the sessionid cookie doesn't get send to the backend.
I was able to fix this in jQuery by setting withCredentials to true.
$("#login").click(function() {
$.ajax({
url: "http://localhost:8080/api/login",
data : '{"identifier" : "admin", "password" : "admin"}',
contentType : 'application/json',
type : 'POST',
xhrFields: {
withCredentials: true
},
success: function(data) {
console.log(data);
},
error: function(data) {
console.log(data);
}
})
});
$("#check").click(function() {
$.ajax({
url: "http://localhost:8080/api/ping",
method: "GET",
xhrFields: {
withCredentials: true
},
success: function(data) {
console.log(data);
}
})
});
The problem that I'm facing is that I can't get this to work in AngularJS with the $http service. I tried it like this:
$http.post("http://localhost:8080/api/login", $scope.credentials, {withCredentials : true}).
success(function(data) {
$location.path('/');
console.log(data);
}).
error(function(data, error) {
console.log(error);
});
Can anyone tell me what I'm doing wrong?
You should pass a configuration object, like so
$http.post(url, {withCredentials: true, ...})
or in older versions:
$http({withCredentials: true, ...}).post(...)
See also your other question.
In your app config function add this :
$httpProvider.defaults.withCredentials = true;
It will append this header for all your requests.
Dont forget to inject $httpProvider
EDIT : 2015-07-29
Here is another solution :
HttpIntercepter can be used for adding common headers as well as common parameters.
Add this in your config :
$httpProvider.interceptors.push('UtimfHttpIntercepter');
and create factory with name UtimfHttpIntercepter
angular.module('utimf.services', [])
.factory('UtimfHttpIntercepter', UtimfHttpIntercepter)
UtimfHttpIntercepter.$inject = ['$q'];
function UtimfHttpIntercepter($q) {
var authFactory = {};
var _request = function (config) {
config.headers = config.headers || {}; // change/add hearders
config.data = config.data || {}; // change/add post data
config.params = config.params || {}; //change/add querystring params
return config || $q.when(config);
}
var _requestError = function (rejection) {
// handle if there is a request error
return $q.reject(rejection);
}
var _response = function(response){
// handle your response
return response || $q.when(response);
}
var _responseError = function (rejection) {
// handle if there is a request error
return $q.reject(rejection);
}
authFactory.request = _request;
authFactory.requestError = _requestError;
authFactory.response = _response;
authFactory.responseError = _responseError;
return authFactory;
}
Clarification:
$http.post(url, {withCredentials: true, ...})
should be
$http.post(url, data, {withCredentials: true, ...})
as per https://docs.angularjs.org/api/ng/service/$http

Resources