How to handle a 401 unauthorized response with Backbone? - javascript

I configure my Backbone router with different views. But on some views, I need to fetch a collection. If the user is not logged in, server returns a 401 http status.
So, I configure jQuery's global ajax settings like that:
$.ajaxSetup({
xhrFields: {
withCredentials: true
},
crossDomain: true,
error: function(jqXHR, textStatus, errorThrown) {
console.log("error ajax");
if (jqXHR.status == 401) {
console.log('error 401');
app.router.navigate('', { trigger: true });
}
}
});
But it never goes in the error callback, even if the response code is 401.

Instead of modifying the ajax options globally, I modified Backbone.sync function to handle authentication.
Backbone.sync = (function(syncFn) {
return function(method, model, options) {
options = options || {};
var beforeSend = options.beforeSend,
error = options.error;
// Add headers
options.beforeSend = function(xhr) {
xhr.setRequestHeader('withCredentials', true);
if (beforeSend) return beforeSend.apply(this, arguments);
};
// handle unauthorized error (401)
options.error = function(xhr, textStatus, errorThrown) {
console.log("error sync");
if (error) error.call(options.context, xhr, textStatus, errorThrown);
if (xhr.status === 401) {
console.log('error 401');
app.router.navigate('', { trigger: true });
}
};
return syncFn.apply(this, arguments);
};
})(Backbone.sync);

Related

Calling sync ready made async ajax javascript function

I want to call this function on button click after login and wait for result, to get token value. This function cannot be changed, it is async and supplied from other currently unavailable team.
I already tried something like this, but with no success. I get web service results, but I can't write appropriate sync call to wait to return token.
function getToken() {
param1 = "123456";
ajax_oauth(param1, function (success, response) {
success: return response.token;
});
}
function ajax_oauth(param1, callback) {
APP.debug("oauth login with param1 " + param1);
try {
APP.blockUI();
var DeviceID = APP.readRegistry(APP_CONFIG.REGISTRY.DeviceID);
//---------------------------------------------------------------
$.ajax(
auth_token_url,
{
method: "GET",
accept: 'application/json',
contentType: "application/json; charset=utf-8",
dataType: 'json',
data: JSON.stringify({
'param1': param1,
'deviceId': DeviceID
}),
xhrFields: {
withCredentials: false
},
statusCode: {
201: function (response) {
APP_STATE.hasOauth = true;
APP.debug('got response 200 from oauth');
auth.login(response.token); //TODO read expiration from token
try {
var decoded = jwt_decode(response.token);
APP_STATE.uid = decoded.uid;
} catch (err) {
APP.error("unable to decode token " + JSON.stringify(err));
}
},
401: function () {
},
500: function () {
},
503: function () {
}
},
success: function (response) {
APP.unblockUI();
APP_STATE.restAvailable = true;
},
error: function (jqXHR, textStatus, errorThrown) {
APP.unblockUI();
APP_STATE.restAvailable = false;
APP.restError(auth_token_url, jqXHR, errorThrown, textStatus);
APP.callback(callback, false);
}
}
);
} catch (err) {
APP.error("unable to do oauth login, " + err);
}
};
After user clicks on login button, I want to call function ajax_oauth and to return token if params ok. If not, to return login error. Login can't be async, as far as I can see.
For whatever reason you can't tap into the original ajax response, you could intercept the request using $.ajaxPrefilter.
From your code it looks like auth_token_url has a global reference. You could use this to intercept the call by matching the outgoing request on the resource URL.
$.ajaxPrefilter('json', function(options, originalOptions, jqXHR) {
if (options.url === auth_token_url) {
jqXHR.done(function(response) {
try {
var decoded = jwt_decode(response.token);
console.log(decoded);
} catch (err) {
APP.error("unable to decode token " + JSON.stringify(err));
}
});
}
});
Note that this needs to be declared well before the request is made preferably after jQuery is loaded.

jQuery ajax requests repeats when error occurs

I've read through several posts related this this kind of issue, but I'm still not identifying the issue here.
When the following function is called and receives a 200 response, all is well; when it encounters 404 the ajax is repeated; adding a timeout only limits the time frame during which the repeat requests are made. There has to be a simple reason for this, but it is eluding me ...
function myFunction(ID) {
var url = 'http://example.org/' + ID;
var response;
$.ajax(url, {
success: function (responseText) {
if (responseText !== undefined) {
response = responseText;
}
},
error: function (xhr, ajaxOptions, errorMsg) {
if (xhr.status == 404) {
console.log('404: ' + errorMsg);
} else if (xhr.status == 401) {
console.log('401: ' + errorMsg);
}
}
});
return response;
}
You can use the below given approach to get the data for your error without repetition in AJAX.
$.ajax(url, {
success: function (responseText) {
if (responseText !== undefined) {
response = responseText;
}
},
error: function (xhr) {
//the status is in xhr.status;
//the message if any is in xhr.statusText;
}
});
UPDATE
You cannot return the response because you have an async request and response variable will be returned before the actual ajax requests gives a response. So I suggest You either use a callback function on success ore use a synchronous request.
So to get the response you can have a function like so:
function getResponse() {
return $.ajax({
type: "GET",
url: your_url,
async: false
}).responseText;
}
Or the callback approach is:
$.ajax(url, {
success: function (responseText) {
if (responseText !== undefined) {
theCallbackFunction(responseText);
}
},
error: function (xhr) {
//the status is in xhr.status;
//the message if any is in xhr.statusText;
}
});
function theCallbackFunction(data)
{
//do processing with the ajax response
}

Customized error messages for $httpProvider.interceptors

We have implemented the below
function Inteceptors($httpProvider) {
'ng-inject';
$httpProvider.interceptors.push('ErrorInterceptor');
$httpProvider.interceptors.push('LoadingInterceptor');
}
function ErrorInteceptor($q, MyNotificationService) {
'ng-inject';
return {
responseError: function(response) {
var msg = JSON.stringify(response.data);
var status = response.status;
console.log('in ErrorInterceptor', response);
if (response.status === -1) {
status = null;
msg = 'An unspecified error occured while trying to make a request'
}
var notification = {
type: 'error',
status: status,
msg: msg
};
MyNotificationService.add(notification);
return $q.reject(response);
}
};
}
This allow errors like 404 and 500 to be intercepted and a message is being prompted to the users.
However, there are certain circumstances that I would like to make use of my own customized error message.
For example when I have a function that makes a call to an API:
this.list = function() {
return $http({
method: 'GET',
url: myendpoint
})
.then(function(response) {
return response.data;
},
function(err) {
return [];
});
}
The response looks like the below in case of 404:
- Object
-- config: Object
- data: Object
- headers: (name)
- status: 404
- statusText: "Not Found"
- __proto__: Object
so if the API returns 404, right now the interceptor is displaying response.data which is "Not found" and status is 404 in response.status
So the message now is
(404) {"detail": "Not found"}
And that is ugly and not helpful!
I would like to provide my own customized messages, how would I achieve that?
If I understand your question correctly then you want to return custom error from ErrorInteceptor() function. You are getting this same error because you are returning response i.e. return $q.reject(response); So try to return your custom message from your service.
Try this
return {
responseError: function(response) {
var status = response.status;
console.log('in ErrorInterceptor', response);
if (response.status === -1) {
status = null;
msg = 'An unspecified error occured while trying to make a request'
}
var notification = {
type: 'error',
status: status,
msg: msg
};
MyNotificationService.add(notification);
return $q.reject(response.statusText);// this is what you should return
}
};

jquery Github api

I'm working on a webpage that I need to display the list of repos by using the github api. But keep get 401 error. Not sure where I was wrong.....
Here is what I have so far:
function requestJSON(url, callback) {
$.ajax({
url: url,
dataType: "json",
complete: function(xhr) {
callback.call(null, xhr.responseJSON);
console.log(xhr.responseJSON);
//alert('Load was performed.');
if (xhr.status === 200) {
alert('User\'s name is ' + xhr.responseText);
}
else {
alert('Request failed. Returned status of ' + xhr.status);
}
},
error: function( req, status, err ) { console.log( 'something went wrong', status, err );
},
beforeSend: function(xhr, settings) { xhr.setRequestHeader('Authorization',authCredentials);
xhr.setRequestHeader('Content-Type', 'text/plain');}
});
}
});
beforeSend: function(xhr, settings) { xhr.setRequestHeader('Authorization',authCredentials);
xhr.setRequestHeader('Content-Type', 'text/plain');}
It was my authCredentials issue, miss type.....

401 Unauthorized Issue

I am using the jQuery.get() method
$.get('login.php', function(d, textStatus, jqXHR){
//alert(jqXHR.status)
var status = jqXHR.status;
if((status==200)||(status==202)){
window.location.href = 'dashboard.html';
}else if(status==401){
alert('Error in login details')
}else{
alert('Unknown Error')
}
});
It is working fine. When 200 & 202 , It will rediredt to dashboard page. But Other than 200 & 202, It pass the error in console but doesn't show alert.
You need to add in some event handlers for the fail state, which will handle 4xx and 5xx errors. The success state only handles HTTP codes which indicate a successful request. From http://api.jquery.com/jQuery.get
var jqxhr = $.get( "example.php", function(data, status) {
alert( "success - " + status );
})
.done(function(data, status) {
alert( "second success - " + status );
})
.fail(function(data, status) {
alert( "error - " + status );
})
.always(function(data, status) {
alert( "finished - " + status );
});
This is because the callback function you have defined is only called when a successful request completes. If the response is anything other than a 200, the request is considered to have errored. To do what you require, you could use the $.ajax() method:
$.ajax({
url: 'login.php',
success: function() {
window.location.assign('dashboard.html');
},
error: function(xhr) {
if (xhr.status == 401) {
alert('Error in login details')
} else {
alert('Unknown Error')
}
}
});

Categories

Resources