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) {
onfig.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.