Basically what I'm trying to do is to set a prefix for all $http server requests (the server url). I tried to use an interceptor, but the problem is that this also affects the template requests:
$httpProvider.interceptors.push(function ($q) {
return {
'request': function (request) {
request.url = "http://localhost/"+request.url;
return request || $q.when(request);
}
}
});
=>
XMLHttpRequest cannot load http://localhost/templates/main.html
I thought about using my own provider (for example $myHttp) which inherit $http, but i don't know how to do this.
So what is a good solution for this?
If all of your templates are in the templates directory, you could just ignore those in your interceptor.
$httpProvider.interceptors.push(function ($q) {
return {
request: function (request) {
if (request.url.indexOf('templates') === -1) {
request.url = "http://localhost/" + request.url;
}
return request || $q.when(request);
}
}
});
Related
I am using angularjs, In backend I check every api authenticated.
Every request should be checked the parameter access_token.
$provide.factory('MyHttpInterceptor', function($q, $location, $localStorage) {
return {
request : function(config) {
config.params = config.params || {};
if ($localStorage.access_token) {
config.params.access_token = $localStorage.access_token;
}
return config || $q.when(config);
},
};
});
// Add the interceptor to the $httpProvider.
$httpProvider.interceptors.push('MyHttpInterceptor');
I using this code. Its working good, but I saw in development tools(Network) the html, css, js files also added the parameters.
like.
http://localhost/webapp/views/template/left-menu.html?access_token=xxxxxxxxxxxxxxxxx
http://localhost/webapp/css/index.css?access_token=xxxxxxxxxxxxxxxxx
But I don't like to send access_token to all http request(html,css,js).
I like to send the access_token for what are have prefix api
http://localhost:9090/api/user/get?access_token=xxxxxxxxxxxxxxxxxxxxxx
//I think the solution is find the http url and grep the text api, if found means add the parameter. Don't konw this is good approach.
Please me the good approach.
I expect only backend api request only.
Also I don't expect every serive http request to add parameter.
Its possible to add common one place in config ?
You can check url:
$provide.factory('MyHttpInterceptor', function($q, $location, $localStorage) {
return {
request : function(config) {
var apiPattern = /\/api\//;
config.params = config.params || {};
if ($localStorage.access_token && apiPattern.test(config.url)) {
config.params.access_token = $localStorage.access_token;
}
return config || $q.when(config);
}
};
});
// Add the interceptor to the $httpProvider.
$httpProvider.interceptors.push('MyHttpInterceptor');
I successfully managed to use interceptors (AngularJs ) in my Ionic application. Previous post .
While it is working perfectly well in the browser using "ionic serve".
There is no content loaded in the header title and content block ( "ion-content" ) using "ionic run android" (either emulating on genymotion or on my own phone). See screenshot below.
I'm pretty sure it comes from the interceptors i'm using, because before that, the app was working on any platforms. Also, as soon as i remove the interceptors it is working again. Here the code.
Note that i'm checking which url is called so i don't go into a circular dependency or checking useless url, only the calls to my api go through.
app.config(function($httpProvider){
$httpProvider.interceptors.push(['$location', '$injector', '$q', function($location, $injector, $q){
return {
'request' : function(config){
// intercept request
// carefull includes might not work while emulating
// use instead indexOf for that case
if(!config.url.includes('/oauth/v2/token') && config.url.includes('/api')){
// inject the service manually
var OauthService = $injector.get('OauthService');
var access_token = OauthService.token();
config.url = config.url+'?access_token='+access_token.key;
}
return config;
}
}
}]);
});
Any ideas what could give this error? (By the way console is showing no errors on browser).
UPDATE :
OauthService.js :
app.factory('OauthService', function($http, $localStorage) {
return {
token : function(){
// Store actual token
access_token = $localStorage.getObject('access_token');
// Store actual identity
identity_token = $localStorage.getObject('identity_token');
// IF no user logged
if(isObjectEmpty(identity_token)){
// IF access_token does NOT exist OR will expires soon
if( isObjectEmpty(access_token) || Date.now() > (access_token.expires_at - (600*1000)) ){
// Create an anonymous access_token
return $http
.get(domain+'/oauth/v2/token?client_id='+public_id+'&client_secret='+secret+'&grant_type=client_credentials')
.then(function (response) {
$localStorage.setObject('access_token', {
key: response.data.access_token,
type: 'anonymous',
expires_at: Date.now()+(response.data.expires_in*1000)
});
return response.data.access_token;
});
}
}
// IF user is logged
else{
// IF access_token does NOT exist OR will expires soon OR is anonymous
if( isObjectEmpty(access_token) || Date.now() > (access_token.expires_at - (600*1000)) || access_token.type == 'anonymous' ){
// Create an access_token with an identity
return $http
.get(domain+'/oauth/v2/token?client_id='+public_id+'&client_secret='+secret+'&api_key='+identity_token+'&grant_type=http://oauth2.dev/grants/api_key')
.then(function (response) {
$localStorage.setObject('access_token', {
key: response.data.access_token,
type: 'identity',
expires_at: Date.now()+(response.data.expires_in*1000)
});
return response.data.access_token;
});
}
}
return access_token.key;
}
};
})
Did you install cordova whitelist plugin ?
cordova plugin add cordova-plugin-whitelist
or if you want to save the reference to your config.xml file:
cordova plugin add cordova-plugin-whitelist --save
If you don't have that your device won't be able to access external resources.
You can find more info here.
UPDATE:
I've checked your previous answer.
The idea of the interceptor is to intercept calls to an external service insert some action in the pipeline.
I would change your interceptor:
$httpProvider.interceptors.push(['$location', '$injector', '$q', '$localStorage', function($location, $injector, $q, $localStorage){
return {
'request' : function(config) {
config.headers = config.headers || {};
access_token = $localStorage.getObject('access_token');
if (access_token) {
config.headers.Authorization = 'Bearer ' + access_token;
}
}
'response' : function(response){
if (response.status === 401) {
logger.debug("Response 401");
}
return response || $q.when(response);
}
'responseError' : function(rejection){
if (rejection.status === 401) {
var OauthService = $injector.get('OauthService');
var access_token = OauthService.token();
if (access_token === null)
{
return $q.reject(rejection);
}
// Append your access token to the previous request and re-submits.
rejection.config.headers['Authorization'] = 'Bearer ' + access_token;
return $injector.get('$http')(rejection.config);
}
// This is necessary to make a `responseError` interceptor a no-op.
return $q.reject(rejection);
}
}
}]);
If you look at the interceptor above it manages all the requests to an external resource (REST api) and appends a bearer token to the authorization header if needed.
The response does not do much as it is only there for logging purposes.
responseError is the place where you should intercept and check if your token as expired, fetch a new one and resubmit the request.
We check if the user is not authorized to the request:
if (rejection.status === 401) { ... }
If not we request a new access token. I guess your OauthService does that.
If we have a new access token:
var access_token = OauthService.token();
we can, again, append the access token to the request header:
rejection.config.headers['Authorization'] = 'Bearer ' + access_token;
and resubmit the previous request:
return $injector.get('$http')(rejection.config);
If you want to find out more about interceptors you can read these blogs.
I am working on project which front end is AngularJS & Backend is Laravel4.
And I am using barryvdh's laravel-debugbar package as debugger
My problem is debugbar showing data when first time load page or i refresh page
But is is not catching when i call api throw angular resourse.
I tried AJAX call configuration as posted in documentation but still not working.
In config file:-
/*
|--------------------------------------------------------------------------
| Capture Ajax Requests
|--------------------------------------------------------------------------
|
| The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors),
| you can use this option to disable sending the data through the headers.
|
*/
'capture_ajax' => true,
And In My Controller:-
Debugbar::addMessage('Another message', 'mylabel');
Debugbar::warning('Watch out..');
Debugbar::sendDataInHeaders();
-ND
After searching longtime on web i got solution for this problem
Kindly add this code to your app.js
.factory('httpInterceptor', function($q) {
var handle_phpdebugbar_response = function(response) {
if (phpdebugbar && phpdebugbar.ajaxHandler) {
var headers = response && response.headers && response.headers();
if (!headers) {
return;
}
var headerName = phpdebugbar.ajaxHandler.headerName + '-id';
var debugBarID = headers[headerName];
if (debugBarID) {
phpdebugbar.loadDataSet(debugBarID, ('ajax'));
}
}
};
return {
request: function(config) {
return config || $q.when(config);
},
response: function(response) {
if (response || $q.when(response)) {
handle_phpdebugbar_response(response);
return response || $q.when(response);
}
},
responseError: function(response) {
handle_phpdebugbar_response(rejection);
return $q.reject(response);
}
};
})
.config(function($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
})
This one is in angular module ng-phpdebugbar
(Laravel5)
Instead of returning your response, send it to a view:
return \View::make('debug', ['data' => $response]);
instead of
return response()->json($response);
(don't forget to create the view where you echo your data)
I implemented Primus (Sockets) on my Server and would like to access it via the client, which uses AngularJS. I would like to be able to still use libraries like Restangular or the $resource from Angular. So IMHO the best way to achieve this is to extend the $http service, which is used by most libraries as the basis.
I would like this new service to be able to gracefully fall back to the normal $http, when there is no socket connection available.
In Pseudocode:
socketHttpService = function(config) {
if(socketEnabled) {
var message = buildMessageFromConfig();
primus.write(message);
return promise;
}
return $http(config);
}
Call it like you would $http
socketHttpService({method: 'GET', url: '/someUrl'}).then(function() {
// do whatever
});
My question is, how can i replace the standard $http service with this newly created one? Is there an elegant way, while still retaining the default $http behaviour?
In the meantime, I found a solution to the problem
.config(function($provide) {
$provide.decorator('$httpBackend', function($delegate, $q, $log, SocketService) {
// do not blast mock $httpBackend if it exists
if (angular.isDefined(angular.mock)) {
return $delegate;
}
var httpBackendSocket = function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
if(SocketService.isOpen) {
console.log('open');
method = method.toLowerCase();
// we only know get, post, put, delete
if(method === 'get' || method === 'post' || method === 'put' || method === 'delete') {
// we can not handle the authentication links via sockets, so exclude them
if( url.substring( 0, '/api/v1/currentuser'.length ) !== '/api/v1/currentuser' &&
!angular.equals(url, '/api/v1/login') &&
!angular.equals(url, '/api/v1/logout') &&
!angular.equals(url, '/api/v1/session') ) {
var promise = SocketService.writeRest(method, url, post || {});
return promise.then(function promiseSuccess(response) {
return callback(response.status, response.data, response.headers, '');
}, function promiseError(response) {
// is caught via http handlers
// LATER: If error, retry with $httpBackend ($delegate)
return callback(response.status, response.data, response.headers, '');
});
}
}
}
return $delegate(method, url, post, callback, headers, timeout, withCredentials, responseType);
}
return httpBackendSocket;
});
})
Why? Because it feels like 5 times faster than http, because there is a standing connection and I am not losing any of the realtime options. It's like a cherry on top.
Kind Regards
I'm trying to figure out if it is possible to use a $http interceptor to cancel a request before it even happens.
There is a button that triggers a request but if the user double-clicks it I do not want the same request to get triggered twice.
Now, I realize that there's several ways to solve this, and we do already have a working solution where we wrap $http in a service that keeps track of requests that are currently pending and simply ignores new requests with the same method, url and data.
Basically this is the behaviour I am trying to do with an interceptor:
factory('httpService', ['$http', function($http) {
var pendingCalls = {};
var createKey = function(url, data, method) {
return method + url + JSON.stringify(data);
};
var send = function(url, data, method) {
var key = createKey(url, data, method);
if (pendingCalls[key]) {
return pendingCalls[key];
}
var promise = $http({
method: method,
url: url,
data: data
});
pendingCalls[key] = promise;
promise.finally(function() {
delete pendingCalls[key];
});
return promise;
};
return {
post: function(url, data) {
return send(url, data, 'POST');
}
}
}])
When I look at the API for $http interceptors it does not seem to be a way to achieve this. I have access to the config object but that's about it.
Am I attempting to step outside the boundaries of what interceptors can be used for here or is there a way to do it?
according to $http documentation, you can return your own config from request interceptor.
try something like this:
config(function($httpProvider) {
var cache = {};
$httpProvider.interceptors.push(function() {
return {
response : function(config) {
var key = createKey(config);
var cached = cache[key];
return cached ? cached : cached[key];
}
}
});
}
Very old question, but I'll give a shot to handle this situation.
If I understood correctly, you are trying to:
1 - Start a request and register something to refer back to it;
2 - If another request takes place, to the same endpoint, you want to retrieve that first reference and drop the request in it.
This might be handled by a request timeout in the $http config object. On the interceptor, you can verify it there's one registered on the current request, if not, you can setup one, keep a reference to it and handle if afterwards:
function DropoutInterceptor($injector) {
var $q = $q || $injector.get('$q');
var dropouts = {};
return {
'request': function(config) {
// I'm using the request's URL here to make
// this reference, but this can be bad for
// some situations.
if (dropouts.hasOwnProperty(config.url)) {
// Drop the request
dropouts[config.url].resolve();
}
dropouts[config.url] = $q.defer();
// If the request already have one timeout
// defined, keep it, othwerwise, set up ours.
config.timeout = config.timeout || dropouts[config.url];
return config;
},
'requestError': function(reason) {
delete dropouts[reason.config.url];
return $q.reject(reason);
},
'response': function(response) {
delete dropouts[response.config.url];
return response;
},
'responseError': function(reason) {
delete dropouts[reason.config.url];
return $q.reject(reason);
}
};
}