12
votes

I am calling a method from the server which returns an error response like (400 & 500 errors) but my AngularJS error callback is not getting called and always the success callback is getting called even though my status code contains 400's or 500's. Can someone please tell what am I doing wrong? Please see the angular & WebAPI code below:

AngularJS code:

$http.get("/api/employee")
    .success(function (data, status, headers, config) {
        console.log(data);
        return data;
    }).error(function (data, status, headers, config) {
        alert("error");
        return status;
});

Web API code:

public HttpResponseMessage Get(EmployeeModel employee)
{
     if (!ModelState.IsValid)
     {
         return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
     }
     //some other code
}
4
can you check the the status of the response in the browsers network tabArun P Johny
Your JavaScript is calling GET but you posted code for PUT. Either use the browser debug tools or Fiddler to see what's going on.Stephen Cleary
Sorry its a typo. Also, this is what the Response I am getting back: HTTP/1.1 400 Bad Request Cache-Control: no-cache Pragma: no-cache Expires: -1 Server: Microsoft-IIS/8.0 X-AspNet-Version: 4.0.30319 X-SourceFiles: =?UTF-8?B?RDpcU2hhblxDb25zdHJ1Y3Rpb25XZWJBcGlcQ29uc3RydWN0aW9uV2ViQXBpXGFwaVxzdXBwbGllcg==?= X-Powered-By: ASP.NET Date: Tue, 29 Oct 2013 21:21:18 GMT Content-Length: 0user972255
What AngularJS version you are using? There is problem with AngularJS version 1.2.[*|rc] version. You can upgrade to latest stable(1.2.9) version, It will work fine.vs4vijay

4 Answers

16
votes

The problem is having an interceptor, which does not propagate the error properly.

When responseError of an interceptor is called it has to propagate the exception up the call stack, so the following function calls / callbacks would know that there is an error coming not a successful response.

$httpProvider.interceptors.push(function ($q, $rootScope) {

        return {
            request: function (config) {
                //the same config / modified config / a new config needs to be returned.
                return config;
            },
            requestError: function (rejection) {
                return $q.reject(rejection);
            },
            response: function (response) {
                //the same response/modified/or a new one need to be returned.
                return response;
            },
            responseError: function (rejection) {
                return $q.reject(rejection);
            }
        };
    });

the point that Matthias mentioned is correct, but it lacks the return element. So if you simply reject in responseError, it doesn't work, you need to return the rejection so the following elements would get notified.

6
votes

I had the same problem, and I'm still figuring this out myself, but I identified a possible problem.

The .error() callback may be prevented from executing, by a HTTP response intercepter (registered by adding to the $httpProvider.interceptors array).

I was using a module for adding interceptors, and so I removed that and wrote the stuff manually.

3
votes

I had created a interceptor to capture delay of each HTTP request and faced the same problem. The solution was very simple. Just replace: return response; with return $q.reject(response);. Example:

SCM.service('httpService', function($q) {
    this.request = function(config) {
        if (angular.isObject(config)) {
            config.delay = new Date().getTime();
        }
        return config;
    };
    this.requestError = function(config) {
        if (angular.isObject(config)) {
            config.delay = new Date().getTime();
        }
        return $q.reject(config);
    };
    this.response = function(response) {
        if (angular.isObject(response.config)) {
            response.config.delay = new Date().getTime() - response.config.delay;
        }
        return response;
    };
    this.responseError = function(response) {
        if (angular.isObject(response.config)) {
            response.config.delay = new Date().getTime() - response.config.delay;
        }
        return $q.reject(response);
    };
});

SCM.config(function($httpProvider) {
    $httpProvider.interceptors.push('httpService');
});
1
votes

I never had luck with the .success and .error options and ended up using .then for everything and have yet to have a problem. I should also point out that you can't return values from a promise like you are trying to do. You have to declare a variable with var before entering the promise or assign a new $scope variable within the promise.

So, with those changes your code would look like this:

var employees = $http({method:'GET', url:'/api/employee');
employees.then(function(data){
    $scope.employeeData = data;
}, function(data){
    //do error handling here
});

Also, having a centralized method for handling errors can be helpful at times, and that can be done using an httpInterceptor (as detailed here: Handle HTTP 302 response from proxy in angularjs). Doing so would allow you to completely remove the second function in the .then if there is no other error handling to be done, thus saving code and bandwidth.