Search code examples
javascriptangularjsajaxxmlhttprequesttimeout

When timeout and when abort occur in $http.get?


AngularJS 1.6.6 has support for differentiation between XHR completion, error, abort, timeout, I have this code snippet which make a request to a url like below:

$http.get(url, {timeout: 1000})
  .then(...)
  .catch(function(error) {
       console.log(error.xhrStatus) // could be abort, complete, error and timeout
   });

When requesting my api takes more than 1 second the promise is rejected with xhrStatus of 'abort', I was wondering in what situation I will get 'timeout' and 'error' status texts?

Edit: It would be awesome if the answer provide the relevant server side code in Web Api


Solution

  • "timeout" will never occur as far as I can tell since the xhr in the $httpBackend never has a timeout property set instead angular uses it's own mechanism for aborting the xhr request if the timeout ms expires or the promise passed in resolves.

    https://github.com/angular/angular.js/blob/master/src/ng/httpBackend.js#L165

    "error" will occur if a request has been dispatched and the network connection has gone down

    If a 500 or 200 comes back the status will be complete but angular will fire the success or error/catch handlers on the http promise depending on the status code.

    Test result model (note I disconnected the network to get the result for test3.php, the test.html page loaded, then I disconnected the network before the setTimeout fired the get hence forcing the xhr.status to error)

    {
      "msg1": {
        "data": {
          "val": "test"
        },
        "status": 200,
        "config": {
          "method": "GET",
          "transformRequest": [
            null
          ],
          "transformResponse": [
            null
          ],
          "jsonpCallbackParam": "callback",
          "timeout": 1000,
          "url": "test1.php",
          "headers": {
            "Accept": "application/json, text/plain, */*"
          }
        },
        "statusText": "OK",
        "xhrStatus": "complete"
      },
      "msg2": {
        "data": null,
        "status": -1,
        "config": {
          "method": "GET",
          "transformRequest": [
            null
          ],
          "transformResponse": [
            null
          ],
          "jsonpCallbackParam": "callback",
          "timeout": 1,
          "url": "test2.php",
          "headers": {
            "Accept": "application/json, text/plain, */*"
          }
        },
        "statusText": "",
        "xhrStatus": "abort"
      },
      "msg3": {
        "data": null,
        "status": -1,
        "config": {
          "method": "GET",
          "transformRequest": [
            null
          ],
          "transformResponse": [
            null
          ],
          "jsonpCallbackParam": "callback",
          "url": "test3.php",
          "headers": {
            "Accept": "application/json, text/plain, */*"
          }
        },
        "statusText": "",
        "xhrStatus": "error"
      },
      "msg4": {
        "data": "",
        "status": 500,
        "config": {
          "method": "GET",
          "transformRequest": [
            null
          ],
          "transformResponse": [
            null
          ],
          "jsonpCallbackParam": "callback",
          "url": "test4.php",
          "headers": {
            "Accept": "application/json, text/plain, */*"
          }
        },
        "statusText": "Internal Server Error",
        "xhrStatus": "complete"
      }
    }
    

    Test.html

    <html>
    <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.js"></script>
    <script>
    angular.module('myApp', [])
      .controller('MyCtrl', function($http){
        var url1 = "test1.php";
        var url2 = "test2.php";
        var url3 = "test3.php";
        var url4 = "test4.php";
    
        var ctrl = this;
    
        ctrl.model={msg1:null, msg2:null, msg3:null, msg4:null}
    
        $http.get(url1, {timeout: 1000})
          .then(function(resp){
            ctrl.model.msg1 = resp
          })
          .catch(function(error) {
            ctrl.model.msg1 = error;
          });
    
        $http.get(url2, {timeout: 1})
          .then(function(resp){
            ctrl.model.msg2 = resp
          })
          .catch(function(error) {
            ctrl.model.msg2 = error;
          });
        setTimeout(function(){
        $http.get(url3)
          .then(function(resp){
            ctrl.model.msg3 = resp
          })
          .catch(function(error) {
            ctrl.model.msg3 = error;
          });
        }, 2000);
        $http.get(url4)
          .then(function(resp){
            ctrl.model.msg4 = resp
          })
          .catch(function(error) {
            ctrl.model.msg4 = error;
          });
    
    
      });
    </script>
    
    </head>
    <body ng-app="myApp" ng-controller="MyCtrl as myCtrl">
    <pre>{{myCtrl.model|json}}</pre>
    </body>
    </html>
    

    test1.php

    <?php
    echo "{\"val\":\"test\"}";
    

    test2.php

    <?php
    sleep(10);
    

    test3.php

    <?php
    sleep(1000);
    

    test4.php

    <?php
    throw new Exception("Error");