ERR_CONNECTION_REFUSED calls my $http sucess function - angularjs

Running my Angular app without a server running should return an error, or course. But this "ERR_CONNECTION_REFUSED" I see in my Chrome's console triggers my success function of my membership service:
function login(user, onSuccess, onError){
$http.post(_loginAddress, user)
.success(loginSuccess)
.success(onSuccess)
.error(loginError)
.error(onError);
}
function loginSuccess(data) {
// this code executes with data = null here.
if (data.ok === true) {
...
}
}
function loginError(data, code) {
...
}
The relevant section of the $http docs states:
A response status code between 200 and 299 is considered a success status and will result in the success callback being called. Note that if the response is a redirect, XMLHttpRequest will transparently follow it, meaning that the error callback will not be called for such responses.
Am I suppose to program my $http success() functions for possible false-positive?
EDIT

So .. I went hunting and found that one of my interceptors (authentication) was causing this ERR_CONNECTION_REFUSED error response to be considered as 'recovered' and therefore the success function was called.
I changed this:
if (response.status !== 401) {
return response;
}
To this:
if (response.status !== 401) {
return $q.reject(response);
}
And everything is fine again.
Hope this might help someone else.

Related

Why is the response with error code (500) treated as successful response while using interceptor

I am trying to use an Angular interceptor for handling my 500 or 403 error codes. For other codes I have custom business implementation. However it seems using interceptor makes Angular treat error responses as success responses and my success callback in .then is called. Isn't this strange, considering docs which says 200-299 codes are only treated as success response.
My code:
function appInterceptorFn(){
var interceptor = {
responseError: function (config) {
if (config && config.status === cramConfig.FORBIDDEN_ACCESS_CODE) {
$rootScope.$emit('ERROR_EVENT', config);
}
return config;
}
}
return interceptor;
}
Is there something that can be done to avoid it, I am using AngularJS v1.3.17
I have visited this link which shows a different implementation but I would like to use interceptor preferably.
Is this a known issue ?
by returning your object "normally", you tell angular to treat your error as a success.
You have to replace your
return config;
with
return $q.reject(config);
Explanation
If you look at the documentation here : https://docs.angularjs.org/api/ng/service/$http#interceptors , you will see the following:
// optional method
'responseError': function(rejection) {
// do something on error
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
}
I know it's not a lot of documentation, but it tells you that if you return an object, or a promise, it will resolve your error as if there was no error. If you want your error to be re-thrown, you have to do it explicitly by using $q.reject()

How do i manually fail an angular $http requests in an interceptor

So i have a server that is returning 200 as a response every time. I need to check the response for an error response.data.error If i find an error i need to send the http request to the catch methods in my application code.
Here is an example of what i want to happen..
interceptor code
// interceptor code
{
response:function(response){
if (response.data.error) {
return $q.reject(response)
}else{
return response
}
},
responseError:function(rejection){
// error handling logic
return $q.reject(rejection)
}
}
app code
// application code
$http.get('/api/stuff')
.then(function(){
// do success stuff
}).catch(function(){
// the function i want to run!!!
})
Try catching the error by:
$http.get('/api/stuff')
.then(function(data){
console.log(data); // do success stuff
}, function(error){
console.log(error); // will catch your error I hope
}
I dont think that .catch will cacth it, you need to preform the check in the .then block.
Ok it was more of a silly mistake. Here is what i did wrong.
like a dumb i returned inside of a function instead of directly inside of the response. so what i ended up doing is creating a flag and if that flag was true then return directly on the response function.
interceptor code
// interceptor code
{
response:function(response){
myCustomErrorFunction(){
if (response.data.error) {
return $q.reject(response)
}else{
return response
}
}
},
responseError:function(rejection){
// error handling logic
return $q.reject(rejection)
}
}
app code
// application code
$http.get('/api/stuff')
.then(function(){
// do success stuff
}).catch(function(){
// the function i want to run!!!
})
Thanks for the help guys.

Can a request interceptor create a http response in angularJS

I am in process of creating Offline mode in an app. Whenever a http request is send, I would want an interceptor to detect the network state. If the state is no connectivity, I would want to create a mock response and make it feel like as if the response is coming from a server.
You could check if you are online or not by reading the status of the response in your interceptor, if its a 401 / 501/ etc:
var interceptor = ['$rootScope', '$q', function ($rootScope, $q) {
function success(response) {
return response;
}
function error(response) {
var status = response.status; // error code
if ((status >= 400) && (status < 500)) {
$rootScope.broadcast("AuthError", status);
return;
}
if ((status >= 500) && (status < 600)) {
$rootScope.broadcast("ServerError", status);
return;
}
// otherwise
return $q.reject(response);
}
return function (promise) {
return promise.then(success, error);
}
}]
There's another way, using html5, but I guess will not work on some browsers. This is done using navigator.onLine property, like:
if (navigator.onLine) {
//I'm online
} else {
I'm not online
}
(https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine)
If you throw an object inside your request interceptor this will trigger a call to the responseError interceptor, passing the throwed object as its argument.
You have to find a way notify responseError interceptor that this is not a real error and that it should return a custom response.
The responseError interceptor can choose to recover error returning a response object o fail returning a rejected promise (check angular's $http interceptor docs)
EDIT: If you throw an object from request interceptor you can't avoid an error message in console. It's better to return a rejected promise passing config object as value and put extra information in it for responseError detect the special situation.

catching 403 errors in angular and showing a pop up

On our site, I get into this predicament where you basically transfer a project over to another user. When that happens, if the original user tries to view the project he/she just transferred, we give a 403 back because they no longer are the owner of the project. I started to look up interceptors in angular. I hooked up the responseError to just see if it gets called on the 403 like so
.config(($httpProvider) => {
$httpProvider.interceptors.push(function() {
return {
responseError: function(rejection) {
console.log("bad response");
return rejection;
}
}
});
});
So my "bad response" gets called and everything, but I was not sure how I could show a modal view or something at this point that shows the error to the user since this 403 response actually happens on a few of our different resources, not just projects. Any thoughts? Thanks in advance.
If i understand correctly you want to show the error dialog only for some http calls not every call that goes through you interceptor. You could probably try this:-
Set a config for your http calls say handleError:true.
$http.get('myurl', {handleError:true})....
$http.post('myurl',data, {handleError:true})....
etc..
and in your interceptor look for that specific config setting to display the error:-
$httpProvider.interceptors.push(function() {
return {
responseError: function(rejection) {
console.log("bad response");
if(rejection.config.handleError && rejection.status === 403){
//show error dialog
}
return rejection;
}
}
});
Also you could possibly send the status code that needs to be handled as well.
$http.get('myurl', {handleStatus:[403,...]})....
and
$httpProvider.interceptors.push(function() {
return {
responseError: function(rejection) {
if((rejection.config.handleStatus || []).indexOf(rejection.status) > -1){
//show error dialog. probably you could show it in a $timeout to make this async.
}
return rejection;
}
}
});

AngularJS ngResource: How to always use the same catch function?

Every time I hit the servers using any $resource I want to show the same alert to my users whenever it fails.
Today, it looks like:
function tryAgain() { alert("try again") }
myResource.query().$promise.catch(tryAgain);
myResource.update(...).$promise.catch(tryAgain);
myResource.delete(...).$promise.catch(tryAgain);
otherResource.query().$promise.catch(tryAgain);
Is there a way to configure the default error handling function for ngResource? I'm looking for something like:
$resource.somethingMagicHere.defaults.catch(tryAgain);
You can use an interceptor in your app.config() section. This will catch all response errors originating from $http which $resource uses.
$httpProvider.interceptors.push(function($q) {
return {
'responseError': function(response) {
if (response.status == 401) {
// Handle 401 error code
}
if (response.status == 500) {
// Handle 500 error code
}
// Always reject (or resolve) the deferred you're given
return $q.reject(response);
}
};
});
The #kba answer helped me find the path. The following article made me understand it:
http://www.webdeveasy.com/interceptors-in-angularjs-and-useful-examples/
Just declare it once and reuse:
var defaultErrorHandler = function() {
alert("try again")
}
myResource.query(...).$promise.catch(defaultErrorHandler());
myResource.update(...).$promise.catch(defaultErrorHandler());
...

Resources