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

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
}

Related

Callback registered with respond is not executed when path is matched

I am trying to test an AngularJS directive which uses an HTML template through a reference. Because of that, it is issuing an http request.
What I am trying to do is capturing all requests for the templates using httpBackend.whenGET("....").respond(function) to load that template from the local store.
The point is that the function is never called. I know it is matching the path because it shows no error saying the call was not expected.
By the way, I prefer to do it this way instead of using html2js.
Let's give an example.
If I set the backend.when wrong (non matching path) I get as error
Error: Unexpected request: GET resources/js/app/views/search/parts/con-search-filter/template.html
No more request expected
If I execute in my code (and I know whenGET gets called):
httpBackend.whenGET(/(.*)template.html/, undefined, undefined,
["basePath"]).respond(function(method, url, data, headers, params){
debugger;
console.log("hello");
return [200, []];
});
Then, the previous error is gone. The point is the breakpoint (debugger;) is not hit and "hello" is not printed.
I am importing angular-mocks v1.5.11 and, according to the documentation, in the line 1255, I should be able to do it
$httpBackend.whenPATCH(/\/user\/(.+)\/article\/(.+)/, undefined, undefined, ['user', 'article'])
.respond(function(method, url, data, headers, params) {
// for url of '/user/1234/article/567' params is {user: '1234', article: '567'}
});
I am using jasmine-maven-plugin version 2.2, with the chrome driver. I am executing the bdd goal.
I have figured it out what it was. Just, the requests were pending and I had to do an httpBackend.flush().

Express.js response status code with jsonp payload

I have a MEAN-stack backend where I'd like to respond with
return res.status(400).jsonp({
message: 'Parsing failed.',
code: '123'
});
When an angular app uses this JSONP endpoint and encounters this particular error, it receives a 400 but without its payload. When I change the status to 200/300 it comes through fine, with 400/500 it doesn't.
On other routes (POST) I can respond with a 4** status code and payload without any issues.
return res.status(400).send({
message: 'Codes do not match.',
code: '234'
});
Any Idea what I'm overlooking?
It looks like this is a browser-thing: when a remote script is requested (as is the case with JSONP requests), and the response returns a 400 (or higher) HTTP status, any code that may still get returned in the response body isn't evaluated (this actually makes perfect sense).
Angular will only know that the response has been sent, and that it had an error status, but since the callback wasn't called, there is no payload data to pass to your callback.
I tested a standalone HTML page:
<script>
function foo(data) { alert('foo') }
</script>
<script src="/endpoint?callback=foo"></script>
And the following Express handler:
app.get('/endpoint', (req, res) => {
return res.status(400).jsonp({ hello : 'world' });
});
A 400 status doesn't trigger the alert, a 200 status does. It also doesn't work if the handler returns plain JS (acting like a simple .js file that gets loaded with a <script src=...>).
So for JSONP requests, you should stick to 200 responses and convey any errors in some other way (like setting an error property in the response object).

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
});

$.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.

destroy always returns with the error callback (although everything seems to be ok)

I'm trying to delete a model on my backend and what I do is this (the code is adapted just to show you the issue, some parts could be missing):
attending= new Backbone.Model();
attending.url= this.url() + "/reject";
attending.set({
id: this.id
})
attending.destroy({
success: function(){
alert("yes");
},
error: function(){
alert("no");
}
});
but what I always obtain is a "no" alert. The fact is the backend seems to be updated correctly and what I obtain as a response too. Here it is:
so... what's wrong with the response I get? Why doesn't backbone recognizes it as a successful response? I get 200/OK and a "application/json" format as well!
Your backend should return something with 200
jQuery expect 200 with application/json to have some content
Have a look here: https://github.com/jashkenas/backbone/issues/2218#issuecomment-20991938
You might want to place a "debugger;" in the error callback and trace exactly why its coming that route vs the success route. That should atleast get your started on the right path...

Resources