How to handle server down requests (AngularJS) - angularjs

I'm making a POST request to a TOMCAT server using AngularJS. Below is a snippet of that code.
$http(<myRequest>).then(function(response) {
$scope.info = response.data;
}, function(response) {
$scope.error = response.data
});
This works fine as long as the server is up and running. In case of any error on the response, it populates the $scope.error variable with the error message. However, if the server is down, when I click the link that makes this request nothing is shown on the page, I can only see the error on the console of the browser.
How do I show this error on the page? I want to somehow notify the user that the server is down.

Regarding the docs:
A response status code between 200 and 299 is considered a success status and will result in the success callback being called.
That said, if your error handler gets called you may check for the status property of the response object. Values in the 400 or 500 range indicate problems that will prevent the server from processing your request. If you are configuring the server yourself, you are able to make up your own error codes and interpret them client side.
$http(<myRequest>).then(function success (response) {
$scope.info = response.data;
}, function error (response) {
if (response.status === <server is down http status>) {
//do something here
$scope.error = "server is down msg";
}
else {
$scope.error = response.data;
}
});
I tried to post data to a non-existent server which gave me the status code -1. If your server is really down, you may have to check for this value.
Edit: There's also a statusText property within your response that could be helpful :)

Related

AngularJS $http get callback not being called with status code 401?

I have the following service that runs when I navigate to a products page:
app.factory('ProductService',['$http','$location',function($http,$location){
var factory = {};
factory.getAll = function(){
$http.get('/products').success(function(response){
console.log('success callback hit');
if(response.status === 401){
console.log(response);
$location.path('login');
}
}).error(function(){
console.log('error');
});
};
return factory;
}]);
In my express router, I check if req.isAuthenticated() and if not (which is the case I'm testing), I call:
return res.status(401).send("Not Authorized");
That's the only place in my server where I send a 401 response, so I know the $http.get(/products) is going to the right place, and I see the get request returning 401 in my console, but why aren't any of my callbacks being hit? (Nothing is logged to the console and I don't get redirected on the client.) I read something about needing to reject the promise if I'm using global interceptors, but I don't think I am using any interceptors? EDIT: This is why I don't think it's a duplicate of the question suggested since I'm not using custom interceptors.
UPDATE: My error handler was getting called, just nothing was logged in my node.js command window (duh, because it's on the client). Thanks for the help everyone!
My error handler was getting called, just nothing was logged in my node.js command window (duh, because it's on the client). Thanks for the help everyone!

Internet Explorer 9 and angular-file-upload not working properly

I'm trying to use upload a file using angular and it works very well except on IE9.
I tried https://github.com/danialfarid/ng-file-upload but requires Flash when working with non-HTML5 browsers, so it does not work for me.
After that I tried https://github.com/nervgh/angular-file-upload and works! Except that after uploading the file I do some processing and maybe return an error by Bad Request. And this does not work in IE9. If the upload is successful my code does not see the Bad Request.
Well, I really don't think that the problem is my code, so I wont post anything here.
What I want is someone who had the same problems to shed me some light in what to do.
EDIT: In other words. In Chrome, status is 400 and in IE9 is 200.
uploader.onCompleteItem = function (fileItem, response, status, headers)
EDIT2: I think I found the source of the error. This is a angular-file-upload function
iframe.bind('load', function() {
try {
// Fix for legacy IE browsers that loads internal error page
// when failed WS response received. In consequence iframe
// content access denied error is thrown becouse trying to
// access cross domain page. When such thing occurs notifying
// with empty response object. See more info at:
// http://stackoverflow.com/questions/151362/access-is-denied-error-on-accessing-iframe-document-object
// Note that if non standard 4xx or 5xx error code returned
// from WS then response content can be accessed without error
// but 'XHR' status becomes 200. In order to avoid confusion
// returning response via same 'success' event handler.
// fixed angular.contents() for iframes
var html = iframe[0].contentDocument.body.innerHTML;
} catch (e) {}
var xhr = {response: html, status: 200, dummy: true};
var headers = {};
var response = that._transformResponse(xhr.response, headers);
that._onSuccessItem(item, response, xhr.status, headers);
that._onCompleteItem(item, response, xhr.status, headers);
But my response is always undefined
I figure out a fix. In my project it only enters the catch statement if the server returned an error. So there I fire the event onError.

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

Why isn't my AngularJS post receiving data from the server?

I am posting to the server using the following in AngularJS:
$http.post('/myurl', {my: "data"}, function(data, status, headers, config) {
console.log("returned");
});
In Chrome Developer Tools, the server is sending back a 200 OK status message. However, my callback is never triggered (i.e. nothing printing to the console). Why is AngularJS not printing the message even though the server returns OK?
I've not seen request written like that, generally you want to do something like:
$http.post('/myurl', {my: "data"})
.success(function(data) {
console.log("returned");
});
or
$http.post('/myurl', {my: "data"})
.then(function(data) {
console.log("returned");
});
you can try
return $http({url: '/myurl' , method: "POST",data:my});
you can also click on F12 chrome console to see the exact error
in order to serr the results data you can add
$http({url: '/myurl' , method: "POST",data:my}).then(
function(result){
console.log(result);
}

angularjs custom REST action and error handling

I'm having some trouble with error handling in a little angularjs application. I'm interacting with a Flask backend and a Postgres DB.
I have a factory service
appointServices.factory('Appointments', ['$resource', function($resource){
return $resource(someUrl, {}, {
query: { ... }
,
create: {
method: 'POST'
,url: 'http://somedomain:port/new/:name/:start/:end/:treatment'
,params: { start: '#start', end: '#end', name: '#name', treatment: '#treatment' }
,isArray:false
}
});
}
]);
Inside a controller I'm making the following call
Appointments.create($scope.appointment, function(value, responseHeaders) {
// success handler
console.debug('success: ', JSON.stringify(value));
}, function(httpResponse) {
// error handler
console.debug('error: ', JSON.stringify(httpResponse));
});
Here $scope.appointment contains the relevant parameters for the create action.
Now, in the backend I'm able to catch DB errors involving constraints and I'm trying to return an error code with a 'meaningful' message. So I have a python method
def create(name, start, end, treatment):
try:
...
transaction_status = 'ok'
code = 200
except IntegrityError as e:
...
transaction_status = 'IntegrityError'
code = 500
finally:
...
return make_response(transaction_status, code)
Everything works fine, I'm able to talk to the backend, create new data and insert this in the DB. As I said, any violation of the constraints is detected and the backend responds
curl -X POST "http://somedomain:port/new/foo/bar/baz/qux" -v
...
< HTTP/1.0 500 INTERNAL SERVER ERROR
...
IntegrityError
So, the problem is, no matter whether the action create was successful or not, the intended error handler specified inside the controller is always fired. Moreover, I always end up with a status code 404 in the httpResponse. Firebug shows correctly the code 500 as above, though.
Anybody has any idea of why I'm getting this behavior?
Any suggestions on how to improve the error handling mechanism are also welcome.
Thx in advance.
P.S. Following the documentation on $resource I have also tried variations on the factory service call, e.g.
Appointments.create({}, $scope.appointment, successCallback, errorCallback);
Appointments.create($scope.appointment, {}, successCallback, errorCallback);
with the same results.
Update:
Forgot to mention the important fact that I'm interacting with the backend via CORS requests. The POST request in create above is having place with the OPTIONS method instead. As I mentioned everything is working correctly except for the error response.
Under further investigation, I tried to isolate the factory service, in case I did something wrong, and I also tried the approach shown in the credit card example ($resource docs), but with no positive result.
However, I came up with two workarounds. Firstly, I was able to create a plain JQuery POST request, as in the example shown in the docs. This time, the request is not replaced by OPTIONS and I got the error code correctly.
I also managed to connect to the backend with the low-level $http service as follows:
var urlBase = 'http://somedomain:port/new/:name/:start/:end/:treatment';
var url = urlBase.replace(/:name/g, $scope.appointment.name);
url = url.replace(/:start/g, $scope.appointment.start);
url = url.replace(/:end/g, $scope.appointment.end);
url = url.replace(/:treatment/g, $scope.appointment.treatment);
// force method to be POST
var futureResponse = $http({ method: 'POST', url: url });
futureResponse.success(function (data, status, headers, config) {
console.debug('success: ', JSON.stringify(data));
});
futureResponse.error(function (data, status, headers, config) {
console.group('Error');
console.debug(JSON.stringify(status));
console.debug(JSON.stringify(data));
console.groupEnd();
});
This time, as in the case of JQuery, the request is done effectively with POST and error codes are correctly received.
Notice also that I'm not calling $http.post but I set the method to POST as part of the object parameter to $http, otherwise the connection takes places with OPTIONS as before.
Still trying to figure out what is happening with $resource.

Resources