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 ...
}
};
}]);
}]);
Related
I am trying to pass an http response from my controller to a service, it works well except for getting the response to go into the controller here is my code below:
For my service
app.factory('ApiService',function($http,Config,$q){
return {
login: function(payload,callBack){
var deferred = $q.defer();
$http({
method:'POST',
url:Config.baseUrl + '/api/login',
data:payload,
headers: {'Content-Type': 'application/json'},
}).then(function successCallback(callBack){
console.log(callBack);
return deferred.resolve(callBack);
}, function errorCallback(callBack){
//deferred.reject(error);
console.log(callBack);
return deferred.reject(callBack);
});
return deferred.promise;
}
}
});
and for the Controller
app.controller('LoginCtrl', function($scope,$position,$rootScope,$state,ApiService) {
$scope.forms = {
'loginForm':''
}
var payload ={
'username':'',
'password':''
}
$scope.userLogin = function(form){
$scope.username = form.username.$modelValue;
$scope.password = form.password.$modelValue;
payload ={
"username":$scope.username,
"password":$scope.password
}
ApiService.login(payload, function(result){
console.log(result);
}
});
Now I don't understand because when I console.log() the response I'm able to see it in the service but doing the same on the controller I'm getting nothing.
No need to make it complex. Simply return promise from factory and use it in controller.
factory:
app.factory('ApiService',function($http,Config,$q) {
return {
login: function(payload) {
return $http({
method:'POST',
url:Config.baseUrl + '/api/login',
data:payload,
headers: {'Content-Type': 'application/json'},
});
}
}
});
in controller :
ApiService.login(payload).then(function(data){
// use response data
}, function(error) {
// handle error
});
You should use it like this:
ApiService.login(payload).then(function(result){
console.log(result);
});
Because you are returning a promise in your service.
Also you don't need that callback parameter, because the then method on the promise is your callback when it finishes and you can access the data your resolve it with.
app.factory('ApiService',function($http,Config,$q){
return {
login: function(payload){
var deferred = $q.defer();
$http({
method:'POST',
url:Config.baseUrl + '/api/login',
data:payload,
headers: {'Content-Type': 'application/json'},
}).then(function (result){
return deferred.resolve(result);
}, function (result){
return deferred.reject(result);
});
return deferred.promise;
}
}
});
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.
My service code:
application.factory('Http', function($http) {
var base_url = "Angular_Database/server.php";
return {
post: function(form_data) {
var request = $http({
method: 'POST',
url: base_url,
data: form_data
});
return request;
},
send: function(request, callback) {
request.then(function(response) {
callback(response);
}).error(function(Object) {
alert(Object.data);
});
}
}
})
here, The problem is in the .then().
My console says:
Type:Error request.then(...) error is not a function
There is no error() function in the HttpPromise object starting from Angular 1.5.X (Based on comment). You need to use catch() function instead of it.
request.then(function(response) {
callback(response);
}).catch(function(Object) {
alert(Object.data);
});
Also could be:
request.then(function(response) {
callback(response);
}, function(error){
alert(error.data);
})
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
});
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);
}
}
};
}]);