I am using $http interceptor to config my http headers.
app.factory('httpRequestInterceptor', ['$q', '$location', 'localStorageService', function ($q, $location, localStorageService) {
var _request = function (config) {
config.headers = config.header || {};
var authData = localStorageService.get('authData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
}
var _responseError = function (rejection) {
if (rejection.status == 401) {
$location.path('/login');
}
return $q.reject(rejection);
}
return {
request: _request,
responseError: _responseError
}
}]);
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push('httpRequestInterceptor');
}]);
Without using $http interceptor (which means if I comment
$httpProvider.interceptors.push('httpRequestInterceptor')
), my post method words fine.
$http.post(RoutePrefix + "api/accounts/create", dataToSend, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).success(function (data, status, headers, config) {
console.log("succes!");
}).error(function (data, status, headers, config) {
console.log("Error!");
});
But if I use $http interceptor,
I will get 415(Unsupported media error).
message: "The request entity's media type 'text/plain' is not supported for this resource."
exceptionMessage: "No MediaTypeFormatter is available to read an object of type 'CreateUserViewModel' from content with media type 'text/plain'."
exceptionType: "System.Net.Http.UnsupportedMediaTypeException"
Any solution or suggestion about my problem? Thanks in advance.
On the line:
config.headers = config.header || {}
The right part is missing an ending s character after header word. Therefore config.headers gets initialised to {} because config.header is undefined.
But, even if it were written config.headers = config.headers || {}, I think it's not necessary at all nor wouldn't have any sense.
Related
I have a login function that works. But, when the user enters an invalid credential, i of course want to display this. But I cant seem to catch the error.
This is my code that works;
function userAccount($resource) {
return {
login: $resource("/Token", null,
{
'loginUser': {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
transformRequest: function (data, headersGetter) {
var str = [];
for (var d in data)
str.push(encodeURIComponent(d) + "=" +
encodeURIComponent(data[d]));
return str.join("&");
}
}
})
}
}
vm.login = function () {
vm.userData.grant_type = "password";
vm.userData.userName = vm.userData.email;
userAccount.login.loginUser(vm.userData,
function (data) {
//login
},
function (response) {
//run this if error (code 400 or similar error)
});
}
});
What do I need to change, to make sure the last bit is run, when to request fails?
EDIT
I found this in the code, and it looks like that is intercepting the error - but how do i get it to, work with my login function, so i can get an error displayed to the user?
.factory('authInterceptor', [
"$q", "$window", "$location", "currentUser", function ($q, $window, $location, currentUser) {
return {
request: function (config) {
if (currentUser.getProfile().token) {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + currentUser.getProfile().token;
}
return config;
},
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
// error handler
}
};
}
])
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}])
When i remove the last 3 lines, and thereby disabling the interceptor, it works, and the error is caught and showed to the user.
So how to make these work together? :)
You need to return the rejection or error object back to the login user requset object like this
.factory('authInterceptor', [
"$q", "$window", "$location", "currentUser", function ($q, $window, $location, currentUser) {
return {
request: function (config) {
if (currentUser.getProfile().token) {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + currentUser.getProfile().token;
}
return config;
},
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
if(ableToREsolve()){
return customRejection
}
return $q.reject(rejection);
}
};
}
])
This in turn will be caught in :
responseError: function(rejection) {
// Show in modal or alert
}
For better understanding I suggest to read on interceptors. Interceptors are of four types:
Request
2.Request Error
3.Response
4.Response Error
In simple words, Interceptors get called before actual
request is passed on to server
response is delivered to client
So in your case error needs to be returned from interceptor in able to be caught by your request object error function.
request
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 have the following factory in my Angular App. It is used to add bearer token information, to the header of all my outgoing request with $resource. It works as expected.
But i have implemented some external calls, which should not be added with the bearer token. How do i implement a check, so i can control what calls are getting intercepted and which are not?
My code:
.factory('authInterceptor', [
"$q", "$window", "$location", "currentUser", function ($q, $window, $location, currentUser) {
return {
request: function(config) {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + currentUser.getProfile().token;
return config;
},
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
// error handler
}
};
}
])
Add the authInterceptor:
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}])
Factory for a resource:
myApp.factory('Random', function ($resource) {
return $resource('domain.com', { }, {
update: {
method: 'PUT'
}
});
});
Call the resource:
Random.query({ });
Any ideas?
There are many ways, for example, you can do something in the request object,
.factory('authInterceptor', [
"$q", "$window", "$location", "currentUser", function ($q, $window, $location, currentUser) {
return {
request: function(config) {
if(config.url !== 'external url') {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + currentUser.getProfile().token;
}
return config;
},
response: function(response) {
return response || $q.when(response);
},
responseError: function(rejection) {
// error handler
}
};
}
])
with that conditional, you will skip unwanted url mods.
check out the doc as well,
https://docs.angularjs.org/api/ng/service/$http#usage
you can even create a key for all calls, that switches the interception on / off.
I implemented jwt stateless in backend , so except login and signup all other method has to intercept in angularjs and sending auth token to server in request header .But token is not sending mean not seeing in reqest header in console(developer tools).
This is my interceptor.js :
/**
*
*/
/* Interceptor declaration */
rootApp.factory('authInterceptor', function ($rootScope, $q, $sessionStorage, $location,$window) {
return {
request: function (config) {
//config.headers['Content-Type'] = 'application/json';
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
//config.headers['x-auth-token'] ='Bearer ' + $window.sessionStorage.token;
}
return config;
},
response: function (response) {
if(response.status === 200){
if(response.data && response.data.success === false){
if($rootScope.authFailureReasons.indexOf(response.data.reason) !== -1){
$location.path('/login');
}
}
}
if (response.status === 401) {
$location.path('/');
}
return response || $q.when(response);
},
'responseError': function (rejection) {
return $q.reject(rejection);
}
};
});
rootApp.config(['$httpProvider', function ($httpProvider) {
// $httpProvider.interceptors.push('headerInterceptor');
$httpProvider.interceptors.push('authInterceptor');
}]);
And service.js file is:
rootApp.service('adminService', function ($rootScope, $http, $q,$window) {
return {
inviteUser: function (user) {
var deferred = $q.defer();
$http({
method: 'POST',
url:$rootScope.baseUrl+'api/v1/admin/user/add',
data:user
}).success(function (response, status, headers, config) {
deferred.resolve(response);
}).error(function () {
// Something went wrong.
deferred.reject({'success': false, 'msg': 'Oops! Something went wrong. Please try again later.'});
});
return deferred.promise;
}
};
});
In server side X-AUTH-TOKEN is allowed in headers too.Where i am going wrong
Please help.
hey I have recently made my first token authentication in my Ionic app .. yeah it is an easy step but implementation may take some time if you are not a language PRO..
you can try this.
https://devdactic.com/user-auth-angularjs-ionic/
this is one of the finest and tested tutorial on the web for token based AUTH..
Maybe that may help you to find the error !
Why is the success callback fired here when the response is 500?
$scope.submit = function() {
var user = $scope.user;
// provide username and password to obtain a token which will be used for api calls
$http.post('/authenticate', user).
success(function(data, status, headers, config) {
$window.sessionStorage.token = data.token;
$location.path('/');
}).
error(function(data, status, headers, config) {
$scope.errors = data.errors;
$scope.message = 'Invalid JSON format, see guidelines for correct format';
$scope.uploadError = true;
console.log('ERROR TRUE');
});
};
And the interceptor:
angular.module('uploadApp')
.factory('authInterceptor',
function ($rootScope, $q, $window, $location) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
},
response: function (response) {
return response || $q.when(response);
},
responseError: function(response) {
if (response.status === 401) {
$location.path('/login');
}
return response || $q.when(response);
}
};
});
The way angular $q promises work is that errors need to be unhandled to continue down the error path - otherwise it assumes that you have corrected the issue or handled the error. So the easiest way is to throw the response from your error path, until you get to the point you actually want to handle it.
angular.module('uploadApp')
.factory('authInterceptor',
function ($rootScope, $q, $window, $location) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' +
$window.sessionStorage.token;
}
return config;
},
response: function (response) {
return response || $q.when(response);
},
responseError: function(response) {
if (response.status === 401) {
$location.path('/login');
}
// instead of returning, you should throw,
// and when you throw you don't need to wrap, as it will
// handle it for you.
//return response || $q.when(response);
throw response;
}
};
});
$q will ensure that the thrown object is wrapped in the promise call-chain. Note that whenever you return in a $q promise it will assume you have handled any issues, unless you throw instead of return. This allows you to have errors in resolvers further down the call-chain that can then be treated as an error.
If throwing isn't your style, you can defer a new promise and return that, then reject it - but that is way less efficient than using the current call-chain.