Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS $http wrong http status on error

I am trying to build a JSONP request with AngularJS's $http Service and on errors I am getting wrong http status code 404 instead of 500, and the body of the page is missing too.

So here is the scenario:

The URL I am calling returns a 500 Internal Server Error with a JSON output containing the error message:

http://private.peterbagi.de/jsfiddle/ng500status/api.php?code=500&callback=test

index.html
(see it in action: http://private.peterbagi.de/jsfiddle/ng500status/ )

<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script src= "//ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
    <script src= "app.js"></script>
</head>
<body ng-app="app" ng-controller="UploadController">
    <button ng-click="upload(200)" value="OK">OK</button>
    <button ng-click="upload(500)" value="Fail">Fail</button>
    <pre>{{response | json}}</pre>
</body>
</html>

app.js

var app = angular.module('app', []);

app.constant('BASE_URL','http://private.peterbagi.de/jsfiddle/ng500status/');

app.controller("UploadController", ['$scope','Upload','BASE_URL',
    function($scope,Upload,BASE_URL) {

    $scope.upload = function(code) {

        Upload(code).then( function(response) {
                $scope.response = response;
            }, function(error) {
                $scope.response = error;
            } );
    }
}]);

app.factory('Upload', ['$http','BASE_URL', function($http,BASE_URL) {
    return function (code) {
        var callUrl = BASE_URL + "api.php?code="+code;
        return $http({
            method: 'JSONP',
            url : callUrl+"&callback=JSON_CALLBACK"
        });
    }
}]);

When you click on the Fail button the returned status is 404 and the response body is missing too.

output

{
  "status": 404,
  "config": {
    "method": "JSONP",
    "transformRequest": [
      null
    ],
    "transformResponse": [
      null
    ],
    "url": "http://private.peterbagi.de/jsfiddle/ng500status/api.php?code=500&callback=JSON_CALLBACK",
    "headers": {
      "Accept": "application/json, text/plain, */*"
    }
  },
  "statusText": "error"
}

In Chrome DevTools Network panel you see the correct response code (500) and I would expect to see the same result in the Angular output.

Why is this happening or what am I doing wrong?

Update:

I built the a similar example, but with GET-Requests instead of JSONP and it works well: http://private.peterbagi.de/jsfiddle/ng500status2/

It seems to be a JSONP specific problem. Nevertheless it doesn't solve my initial problem, because I have to work with Cross-Domain Requests. Any ideas?

like image 625
buggy1985 Avatar asked May 20 '16 16:05

buggy1985


1 Answers

According to the angular source's httpBackend.js line 63 and line 190,

the status of a 'JSONP' request can only be -1, 404, or 200.

The reason is that in angular 'JSONP' request is not an XMLHttpRequest. AFAIK there is no way to handle the specific error code in this way. The only thing javascript know is whether this request succeeded.

UPDATE:

Here in my answer above:

the status of a 'JSONP' request can only be -1, 404, or 200.

This means the status given by angular for the response of this request.

XMLHttpRequest is the standard request type we normally used in ajax.It sends request to the server and fetch the response so you can see the HTTP status code(200,404,500,401,etc.) given by the server side.

However, it has limits like in most cases you cannot make a cross-domain XMLHttpRequest (unless you've set up the allow-cross-domain header on the server side).

In this way we need JSONP to help us make cross-domain requests. In fact 'jsonp' is appending <script> tags to your document (which are always removed when request finished) whose src attributes are the URLs you given.

In angular, listeners are added to this <script> to track the status of the request. However, these listeners can only tell whether the script is loaded successfully. If it succeeded, angular set the status of your response to 200. If not, 404 is assigned. That is why the status field is either 404 or 200, regardless of what the server actually gives.

like image 93
MMhunter Avatar answered Nov 18 '22 06:11

MMhunter