Angular - How to properly handle an HTTP error from server? - angularjs

Currently I've got this:
$http({
method: 'POST',
url: 'http://api-endpoint/somescript/',
data: formData,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(function (response) {
console.log(response);
});
If the script on the other end works out ok, then gets called. However, let's say the script on the server end has some sort of error that's not properly caught. If I make up an error by tossing in some garbage call like asdfasdf(), the then function isn't called, and instead I get this in the browser console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://api-endpoint/somescript/. (Reason: CORS
header 'Access-Control-Allow-Origin' missing).
How do I catch this in the Angular code so I can handle it in a user-friendly manner?
EDIT: This is not a duplicate, as it is specific to Angular.

The $q.then() method accepts three function parameters, the first being the handler for a successful callbacks, the second being for errors, and the third being for notify. $http leverages $q behind the scenes so this thenable should behave like the documentation suggests.
To handle errors in the above code, just toss in an additional function for error handling as such:
.then(function (response) {
console.log(response);
}, function(response) {
console.log(response);
});
Feel free to browse the $q documentation, specifically The Promise API, for additional details.

To handle this, we will have to add a service/factory to intercept http calls. You can do it like this in your config
$httpProvider.interceptors.push('httpRequestInterceptor');
Now, the above service will be something like this
angular.module("app").factory('httpRequestInterceptor', function ($q) {
return {
'request': function (config) {
// Extract request information
return config || $q.when(config);
},
'responseError': function(rejection) {
// Extract response error information and handle errors
return $q.reject(rejection);
}
}
});

Related

Response is undefined in success $http call angularJS

Although my backend is working correctly and I'm getting correct response from Postman crafted request
I can't see response in my angularJS controller. ( i execute this call inside controller to simplify situation )
$scope.click = function (auction_id) {
$http({
url: baseUrl + 'auctions/' + auction_id +'/followers',
headers: {
'Content-Type' : 'application/vnd.api+json'
},
method: 'POST'
})
.then(function(response) {
console.log(response);
})
.catch(function(response) {
return response;
});
};
I'm passing token with httpInterceptor which is working fine for the rest of my app.
URL is correct because I'm getting valid error number in console:
POST ##################/v1/auctions/172/followers
422 (Unprocessable Entity)
CategoryCtrl.js:64 undefined
64 line is that one console log in success .then(function....
Headers in (which I believe is) response headers from postman tab (third from Body in first screenshot)
Why response is undefined?
*Hashes in url code are mine.
From your REST API request, you're getting response with status 422, that means you've got a client error. Regarding your request, you have to handle a request when error will come. To handle error in asynchronous requests there is a second parameter of .then(mySuccessMethod(), myMethodOnError()) method.
More details about .then() and .catch() methods for promisses.
$scope.click = function (auction_id) {
$http({
url: baseUrl + 'auctions/' + auction_id +'/followers',
headers: {
'Content-Type' : 'application/vnd.api+json'
},
method: 'POST'
})
.then(function(response) {
console.log(response);
}, function(error) {
// Here goes your code to handle an error with status 4XX
console.log(error)
})
.catch(function(response) {
// Catch will come when you throw an error
return response;
});
};
When you made the request in Postman, you pass the token in the Auth attribute of the header in the request. In your code, you did not.

Creating custom header for $http in AngularJs

In my controller i want send a request using get method if $http, in that get method i want to send the sessionID in headers. Below am giving the code snippet please check.
this.surveyList = function () {
//return session;
return $http.get('http://op.1pt.mobi/V3.0/api/Survey/Surveys', {headers: { 'sessionID': $scope.sessionid}})
.then(function(response){
return response.data;
}, function(error){
return error;
});
}
but this is not working when i send this vale in backend they getting null.
So how to resolve this.
we have a issue where the api is getting called twice from angular , however it works only once when called with the POSTMAN. And here with the custom header passed to the api, the action is called twice. What could be the reason for it?
Try in this way,
$http({
method: 'GET',
url: 'http://op.1pt.mobi/V3.0/api/Survey/Surveys',
headers: {
'sessionId': $scope.sessionid
}
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs,
// or server returns response with an error status.
});

errorCallback in $http.get().then is never called

I use the the simplest $http.get().then construction, but errorCallback is never called (checked with 500 and 404 error code)
$http.get(url,{cache: pageCache}).then(
function(data){
console.log('getPage.SUCCESS');
console.log(data);
console.log(data.data);
},
function(data){
console.log("ERROR");
console.log(data);
}
);
HTTP HEADERS
I also tried success/error - but the same issue is arrised
As described here, interceptor's responseError function have to be ended with return $q.reject(rejection);
One of my interceptors didn't follow this rule and cause all this mess
It may be that you are using the .then function which returns an object called response that contains several objects one of which is data.
The following is an example from https://docs.angularjs.org/api/ng/service/$http
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
The response object contains a status object, angular uses this to run either the success callback or the error callback.
Then to access your data object use response.data, or what I like to do is have a service that returns only what I need to avoid confusion in the controller.

$httpProvider interceptor not intercepting my API calls

I have an angular application making async requests to an API service. Since a lot of the resources are protected on the API Service, I need to intercept the HTTP requests made to the service. But as far as I can see, the interceptor I have defined only intercept page load requests.
Here is an experimental setup I have come up with to illustrate my problem:
myApp = angular.module('myApp', []);
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function() {
return {
response: function(response) {
console.log(response);
return response;
}
};
});
});
What I am able to see is that, the interceptor intercepts all calls except the API call as you can see from the attached screen shot showing the console output.
The console output, as you can see from the screen shot below, contains the responses logged when the partial templates have been loaded but not when the GET request was made to the API service.
Why does this happen?
Update
I have changed my setup to include all possible combinations of requests and responses now:
$httpProvider.interceptors.push(function() {
return {
request: function(request) {
console.log(request);
return request;
},
requestError: function(request) {
console.log(request);
return config;
},
response: function(response) {
console.log(response);
return response;
},
responseError: function(response) {
console.log(response);
return response;
}
};
});
Now the interceptor intercepts the message but weirdly shows the status of the caught responseError as:
status: -1
although it clearly is a 401.
Update 2
As it turns out, even 401 responses require the CORS header to be added to it. The problem came up since the REST API I was calling used Spring-CORS library which does not include CORS headers on 401 and 403 responses.
It's a cross-site domain issue because although your using localhost your API call domain is different to the UI's (port 8080 & 8081), have a read of this article for more information. You will need add this header in your webserver:
Access-Control-Allow-Origin: http://foo.example
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

angular $http not returning .error() variables if CORS headers are missing from the response

I'm executing an $http.get over websockets and somehow the .error doesn't populate any of the parameters. I'm using angular 1.3.5 and latest Chrome on OSX and local host is aliased to mywebsite.com.
$http({method: 'GET', 'ws://mywebsite.com/resource'})
.success(function(response){ ... })
.error(function(err, status){
console.log(err); <<< here err and status are null respectively 0 even the XHR Response logs 401 in console.
});
Any clues why this is doing so? No mater what error code it is, it doesn't get passed to error callback. For 2xx response i do get the data and all is fine.
Just to clarify, the .error callback gets called as normal, but err and status re not populated.
Well, well, I discovered what was happening. A combo of things.
First I'm using KOA and the above angular hits the KOA as REST API. I'm also using koa-jwt to auth the users and generate a token.
Now the api runs on a subdomain and even i set the CORS via koa-cors to allow * access.
The issue is that koa-jwt when the token is expired, they simply do a this.throw(401). The way KOA handles that it so immediately terminate subsequent middleware and exit with that error. THAT, didn't allow koa-cors headers to be set, regardless where I put that middleware (before or after koa-jwt).
Hence, the elegant fix was to wrap my top level yield next in a try catch and avoid allowing koa-jwt ctx.throw to propagate.
On Angular side, the browser was refusing to convey the 401 to the .error complaining it didn't find a suitable CORS to allow it to process and hand over the response :).
app.use(cors({origin:"*", methods:'GET,HEAD,PUT,POST,DELETE,PATCH'})); //allow all origins to the API.
app.use ( function *(next){
try {
yield next;
} catch (err) {
this.status = err.status || 500;
this.body = err.message;
this.app.emit('error', err, this);
}
});
... more middleware
// middleware below this line is only reached if jwt token is valid
app.use(jwt({secret: config.app.secret}));
Allowing a this.trow(401) from koa-jwt will ruin your day.
I think you just make a typo, just write like this:
$http({method: 'GET', 'ws://mywebsite.com/resource', headers: headers})
.success(function(response){ ... })
.error(function(err, status){
console.log(err);
});
However as a best practice I would do as
var request = {
method: 'GET',
url: 'ws://mywebsite.com/resource',
headers: {//insert here header you want, put Origin header only for example purposes
Origin: 'ws://mywebsite.com/resource'
}
}
$http(request)
.success(function(response){ ... })
.error(function(err, status){
console.log(err);
});
If the typo is not the error (you may copied the code) just look at this AngularJS $http error function never called

Resources