Abort JSONP request AngularJs - angularjs

I have the following code:
var canceler = $q.defer();
$http.jsonp(urlWithParams, {
timeout : canceler.promise
}).error(function(data, status, headers, config) {
...
}).success(function(data) {
...
}
});
canceler.resolve();
The error handler of the request gets executed however in the network log of both Firefox and Chrome give 200 responses and return the JSON response. So while the application behaves like the request was aborted, in reality it wasn't? When canceling the request I would have expected the request to have been aborted than returning a 200 success.

You're not doing anything wrong.
Generally, because http is stateless, you can't abort a request once it's been sent to the server. You can, however, stop waiting for and ultimately ignore an eventual response - as you are doing here.
Unless you feel that the error handler shouldn't have been fired because the response succeeded? You don't say whether you're concerned that it was incorrectly failed, or that the aborted request received a response.

The final statement in your code canceler.resolve() will trigger the error. From the angularjs docs:
timeout – {number|Promise} – timeout in milliseconds, or promise that should abort the request when resolved.
So I think if you don't call canceler.resolve() it won't call the error function.

Related

Why does angularjs discard the message response for http status codes <200 && >300?

I've been tracking down the reason why I cannot see the response from my webapi in angularjs using $http if the status code is less than 200 and greater than 300.
I've debugged angular.js to the point where I understand whats happening (basically its discarding the promise that contains the data i care about and creating a new one without it if the status codes are not deemed a success)
-see code at https://github.com/angular/angular.js/blob/master/src/ng/q.js#L270-L280
this.$$state.value (holds the http respone) is lost at this point for some reason.
Does it make sense to omit the original values? I'm not going to submit a bug report without asking here if I'm right or wrong.
The reason behind all this is that I am processing some credit card info on the server side. If the processor says its an invalid card, I wouldn't think it would be a 200 code, would it? See the answer to this question..... Suggesting 400 for business rules. This still fails in angularjs.
What is the appropriate HTTP status code response for a general unsuccessful request (not an error)?
Also, FYI, httpInterceptors do not work either, since they are utilized after this 'promise replacement' occurs.
From the Docs:
A response status code between 200 and 299 is considered a success status and will result in the success callback being called. Any response status code outside of that range is considered an error status and will result in the error callback being called.
— AngularJS $http Service API Reference - General Usage
The $http service rejects responses outside of the range of 200 to 299 but it does not "discard the message response". Both the resolve and the reject methods of the $http promise are invoked with the entire response object.
This means all of the data is available in the rejection handler.
var dataPromise = $http(configObject)
.then (function onFulfilled(response) {
//return data for chaining
return response.data;
})
.catch (function onRejected(response) {
if (response.status == 400) {
console.log("400 Bad Request");
console.log("REASON:", response.data);
//chain with default data
return defaultData;
} else {
//throw to chain rejection
throw response;
}
});
In the above example, the rejection handler logs the response for messages with status 400 and converts the rejection to fulfilled with default data. All other status responses get chained as a rejection.
Data is not discarded; it is available and can be used in the rejection handler.
For more information on chaining promises, see Angular execution order with $q.
Do you write status codes when you use promise callbacks then, catch and finally after the $resource call.
Here is what I would check for :
MyRestAPI.XXX({resource}, {data}, MyCallbackFunction).$promise.catch(function(response) {
//should be called upon error
//check response.status for HTTP code.
}).then(function() {
// OK
});

XHR.statusText error when aborting angular $http requests

So I have recently implemented a means to cancel an $http request via the timeout property by passing in and resolving a promise.
When a request is aborted the $http promise goes to the error block. This is all fine, its after this all finishes processing I receive an error from angular.js (xdomain.js is in the call stack) stating that it "Cannot read property 'statusText' of null". Null being the xhr object.
I'm at a loss currently as the request is successfully being cancelled, but it seems as if the xhr object is being destroyed right after calling xhr.onload().
Here's an example of how I'm cancelling the request:
var request = {
url: 'someurl',
method: 'get',
headers: headers
timeout: canceller // this is a promise that I resolve in a controller in order to abort an $http request. This works fine.
}
$http(request).then(function () {
//success block
}, function () {
// error block
});
As I said, it enters the error block but it isn't inside of that block that the angular error is thrown, rather it seems to be with the request comes back and there is no longer an xhr object waiting for it that an error occurs.
This is a common problem with Angular and Xdomain. A workaround I'm fond of is passing in a unique identifier or bool when submitting the request. If the value has changed when the request is completed simply ignore the results.

$.ajax works, $http does not (status 0; CORS?)

I have a cloud service I am attempting to download data from. I can use jQuery's $.ajax function to obtain this data with no issue - all status codes expected are returned.
AngularJS is a different story and I have no idea why. I am using the $http service to get(...) my data. I know there are a few errors the $http is likely to fail on (a 404 if the user mistypes something in the registration box, or a 403 if they are not authenticated).
Yet, no matter what I attempt - I receive a status: 0 response everytime and this is pretty useless as you can imagine.
I have a basic function as follows:
function get(config) {
$ionicLoading.show();
return $http(config)
.then(function (data) {
console.log(data);
return data.data;
},
function (data) {
console.log(data);
throw 'Connection error';
})
.finally(function () {
$ionicLoading.hide();
}
);
}
I use this to test the connection of one of my cloud services.
Which is fine; however - if I pass it an incorrect subdomain for my service, e.g. incorrect.myservice.com - I receive the following error:
GET https://incorrect.myservice.com/ net::ERR_NAME_NOT_RESOLVED
Which is good - that should result in a 404 error(?).
But, the data returned in the error callback is:
Object {data: "", status: 0, headers: function, config: Object, statusText: ""}
Which is bad - it should not be 0? It should be 404. I done some research, and it appears that CORS is a bit of a headache in AngularJS $http.
However, from what I have read - it appears that CORS is enabled on my server because looking at the response in Fiddler/Chrome/IE etc., all responses are returning the Access-Control-Allow-Headers: * and Access-Control-Allow-Headers: * which is what is required for CORS.
So I am completely lost on how to further debug this, as I require this functionality in my application. But $http does not appear to be behaving how it should be?
Please can somebody assist and provide a pointer.
All error codes are returning with status: 0 and I have no idea why?
GET https://incorrect.myservice.com/ net::ERR_NAME_NOT_RESOLVED
Which is good - that should result in a 404 error(?).
Nope. If you can't resolve the host name to an IP address, you can't make a TCP connection to it, so you can't even send the HTTP GET, and if you can't send the request, you can't get the response, which is where the 404 would come from. This is a lower level networking error and you don't even get to do any HTTP, so you get no HTTP status code.
This is also not a CORS error. The browser (at least Chrome) will print a really clear and explicit error message if anything goes wrong with CORS.

angularjs $http cache, will it cache server errors

In angular $http.get(url, {cache:true}) will nicely cache server responses. But what does the cache do when the GET request to the server fails? This could be a temporary connection issue or a server response like a timeout.
Suppose I handle the error and display a retry button, will a subsequent call to $http.get(url, {cache:true}) retry the server or will it give me a failed promise from the cache?
If multiple requests are made to the same GET url the cache will cause there to only be one request. Quoting the documentation:
If there are multiple GET requests for the same URL that should be cached using the same cache, but the cache is not populated yet, only one request to the server will be made and the remaining requests will be fulfilled using the response from the first request.
However, when that request returns if the status code is not successful it will not be cached (it will be removed from the cache).
We can see this in the source code:
/**
* Callback registered to $httpBackend():
* - caches the response if desired
* - resolves the raw $http promise
* - calls $apply
*/
function done(status, response, headersString, statusText) {
if (cache) {
if (isSuccess(status)) {
cache.put(url, [status, response, parseHeaders(headersString), statusText]);
} else {
// remove promise from the cache
cache.remove(url);
}
}
So in short - Angular will not cached 'failed' requests - that is: requests with a non-success status code.

Ext.Ajax.request() invokes the failure callback function upon successful request

I'm building a PhoneGap - Sencha-touch application for the iOS and Android platforms. I am loading a local .js file using the Ext.Ajax.request() function.
Funny thing happens - the requests succeeds, but the the 'failure' callback is called.
Here is the code:
Ext.Ajax.request({
url: 'localfolder/foo.js',
success : function(xhr){
// not invoked
},
failure : function(response, options){
// response.status == 0
// wtf, response.responseText contains exactly the contents of the local .js file!
}
});
Anyone has an Idea why the 'failure' callback is triggered when in fact the request succedded?
[edit]
More importantly, how do I make the 'success' callback to be triggered instead?
Ext.Ajax simply examines the status code of the underlying XHR (XmlHttpRequest) object it creates. However, it (incorrectly) assumes that the status is an HTTP status. As this Mozilla-provided article discusses, when file: or ftp: schemes are used, a status value of 0 indicates success.
You can modify the onComplete function in Ext.data.Connection (in src/data/Connection.js) to look at the scheme of the URL, and decide if it should use an HTTP-based status or a "0=OK" status to determine success.
It is perfectly legal for non-success results to have a body that can be used by the client. This is why your response.responseText still shows up correctly.
I usually using response like this, maybe it'll help
{
success:true, // success status
data: [] // data from process
}

Resources