【问题标题】:How to use HTTP.GET in AngularJS correctly? In specific, for an external API call?如何在 AngularJS 中正确使用 HTTP.GET?具体来说,对于外部 API 调用?
【发布时间】:2013-12-20 14:03:51
【问题描述】:

我在controller.js中有如下代码,

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

myApp.service('dataService', function($http) {
delete $http.defaults.headers.common['X-Requested-With'];
this.getData = function() {
    $http({
        method: 'GET',
        url: 'https://www.example.com/api/v1/page',
        params: 'limit=10, sort_by=created:desc',
        headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
     }).success(function(data){
         return data
    }).error(function(){
        alert("error");
    });
 }
});

myApp.controller('AngularJSCtrl', function($scope, dataService) {
  $scope.data = dataService.getData();
});

但是,我想我可能在 CORS 相关问题上犯了一个错误。你能指点我打这个电话的正确方法吗?非常感谢!

【问题讨论】:

  • 这是一个超级常见的问题:)

标签: javascript angularjs http get cross-domain


【解决方案1】:

以 Google 财经为例,检索代码的最后收盘价和更新的日期和时间。您可以访问 YouTiming.com 进行运行时执行。

服务:

MyApp.service('getData', 
  [
    '$http',
    function($http) {

      this.getQuote = function(ticker) {
        var _url = 'https://www.google.com/finance/info?q=' + ticker;
        return $http.get(_url); //Simply return the promise to the caller
      };
    }
  ]
);

控制器:

MyApp.controller('StockREST', 
  [
    '$scope',
    'getData', //<-- the service above
    function($scope, getData) {
      var getQuote = function(symbol) {
        getData.getQuote(symbol)
        .success(function(response, status, headers, config) {
          var _data = response.substring(4, response.length);
          var _json = JSON.parse(_data);
          $scope.stockQuoteData = _json[0];
          // ticker: $scope.stockQuoteData.t
          // last price: $scope.stockQuoteData.l
          // last updated time: $scope.stockQuoteData.ltt, such as "7:59PM EDT"
          // last updated date & time: $scope.stockQuoteData.lt, such as "Sep 29, 7:59PM EDT"
        })
        .error(function(response, status, headers, config) {
          console.log('@@@ Error: in retrieving Google Finance stock quote, ticker = ' + symbol);
        });
      };

      getQuote($scope.ticker.tick.name); //Initialize
      $scope.getQuote = getQuote; //as defined above
    }
  ]
);

HTML:

<span>{{stockQuoteData.l}}, {{stockQuoteData.lt}}</span>

在 YouTiming.com 主页的顶部,我放置了关于如何在 Chrome 和 Safari 上禁用 CORS 策略的注释。

【讨论】:

    【解决方案2】:

    首先,您的success() 处理程序只返回数据,但不会返回给getData() 的调用者,因为它已经在回调中。 $http 是一个异步调用,它返回一个$promise,所以你必须注册一个回调来等待数据可用。

    我建议在 AngularJS 中查找 Promises 和 $q library,因为它们是在服务之间传递异步调用的最佳方式。

    为简单起见,以下是使用调用控制器提供的函数回调重写的相同代码:

    var myApp = angular.module('myApp',[]);
    
    myApp.service('dataService', function($http) {
        delete $http.defaults.headers.common['X-Requested-With'];
        this.getData = function(callbackFunc) {
            $http({
                method: 'GET',
                url: 'https://www.example.com/api/v1/page',
                params: 'limit=10, sort_by=created:desc',
                headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
            }).success(function(data){
                // With the data succesfully returned, call our callback
                callbackFunc(data);
            }).error(function(){
                alert("error");
            });
         }
    });
    
    myApp.controller('AngularJSCtrl', function($scope, dataService) {
        $scope.data = null;
        dataService.getData(function(dataResponse) {
            $scope.data = dataResponse;
        });
    });
    

    现在,$http 实际上已经返回了一个 $promise,所以可以重写:

    var myApp = angular.module('myApp',[]);
    
    myApp.service('dataService', function($http) {
        delete $http.defaults.headers.common['X-Requested-With'];
        this.getData = function() {
            // $http() returns a $promise that we can add handlers with .then()
            return $http({
                method: 'GET',
                url: 'https://www.example.com/api/v1/page',
                params: 'limit=10, sort_by=created:desc',
                headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
             });
         }
    });
    
    myApp.controller('AngularJSCtrl', function($scope, dataService) {
        $scope.data = null;
        dataService.getData().then(function(dataResponse) {
            $scope.data = dataResponse;
        });
    });
    

    最后,有更好的方法来配置$http 服务来为您处理标头,使用config() 来设置$httpProvider。查看$http documentation 获取示例。

    【讨论】:

    • @Kevin:我是 ANG 新手,我不清楚,为什么不在你重新编写的代码中的服务中使用 .success 和 .error 方法?我们需要在控制器中使用它吗?如何 ?任何示例来显示成功/错误和数据、配置参数?
    • 我使用.then(),它是promise 接口,它与.success() 基本相同,但可以链接。 .success/.error 基本上已被承诺弃用
    【解决方案3】:

    调用服务或工厂中定义的承诺时,请确保使用服务,因为我无法从工厂中定义的承诺中获得响应。这就是我如何称呼服务中定义的承诺。

    myApp.service('serverOperations', function($http) {
            this.get_data = function(user) {
              return $http.post('http://localhost/serverOperations.php?action=get_data', user);
            };
    })
    
    
    myApp.controller('loginCtrl', function($http, $q, serverOperations, user) {        
        serverOperations.get_data(user)
            .then( function(response) {
                console.log(response.data);
                }
            );
    })
    

    【讨论】:

      【解决方案4】:

      不需要用 $http 承诺,我只用它有两个回报:

       myApp.service('dataService', function($http) {
         this.getData = function() {
            return $http({
                method: 'GET',
                url: 'https://www.example.com/api/v1/page',
                params: 'limit=10, sort_by=created:desc',
                headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
            }).success(function(data){
              return data;
            }).error(function(){
               alert("error");
               return null ;
            });
         }
       });
      

      在控制器中

       myApp.controller('AngularJSCtrl', function($scope, dataService) {
           $scope.data = null;
           dataService.getData().then(function(response) {
               $scope.data = response;
           });
       }); 
      

      【讨论】:

        【解决方案5】:

        所以你需要使用我们所说的promise。在此处阅读 Angular 如何处理它,https://docs.angularjs.org/api/ng/service/$q。将我们的 $http 支持承诺变成固有的,所以在你的情况下,我们会做这样的事情,

        (function() {
          "use strict";
          var serviceCallJson = function($http) {
        
              this.getCustomers = function() {
                // http method anyways returns promise so you can catch it in calling function
                return $http({
                    method : 'get',
                    url : '../viewersData/userPwdPair.json'
                  });
              }
        
          }
        
          var validateIn = function (serviceCallJson, $q) {
        
              this.called = function(username, password) {
                  var deferred = $q.defer(); 
                  serviceCallJson.getCustomers().then( 
                    function( returnedData ) {
                      console.log(returnedData); // you should get output here this is a success handler
                      var i = 0;
                      angular.forEach(returnedData, function(value, key){
                        while (i < 10) {
                          if(value[i].username == username) {
                            if(value[i].password == password) {
                             alert("Logged In");
                            }
                          }
                          i = i + 1;
                        }
                      });
                    }, 
                    function() {
        
                      // this is error handler
                    } 
                  );
                  return deferred.promise;  
              }
        
          }
        
          angular.module('assignment1App')
            .service ('serviceCallJson', serviceCallJson)
        
          angular.module('assignment1App')
          .service ('validateIn', ['serviceCallJson', validateIn])
        
        }())
        

        【讨论】:

          【解决方案6】:

          试试这个

          myApp.config(['$httpProvider', function($httpProvider) {
                  $httpProvider.defaults.useXDomain = true;
                  delete $httpProvider.defaults.headers.common['X-Requested-With'];
              }
          ]);
          

          仅设置 useXDomain = true 是不够的。 AJAX 请求也与 X-Requested-With 标头一起发送,这表明它们是 AJAX。删除标头是必要的,因此服务器不会拒绝传入的请求。

          【讨论】:

            【解决方案7】:

            我建议你使用 Promise

            myApp.service('dataService', function($http,$q) {
            
              delete $http.defaults.headers.common['X-Requested-With'];
              this.getData = function() {
                 deferred = $q.defer();
                 $http({
                     method: 'GET',
                     url: 'https://www.example.com/api/v1/page',
                     params: 'limit=10, sort_by=created:desc',
                     headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
                 }).success(function(data){
                     // With the data succesfully returned, we can resolve promise and we can access it in controller
                     deferred.resolve();
                 }).error(function(){
                      alert("error");
                      //let the function caller know the error
                      deferred.reject(error);
                 });
                 return deferred.promise;
              }
            });
            

            所以在你的控制器中你可以使用该方法

            myApp.controller('AngularJSCtrl', function($scope, dataService) {
                $scope.data = null;
                dataService.getData().then(function(response) {
                    $scope.data = response;
                });
            });
            

            promises 是 angularjs 的强大功能,如果你想避免嵌套回调,它特别方便。

            【讨论】:

            • $http 已经返回了一个承诺。将 $http 包装在另一个 Promise 中是多余的。
            • 在 $http 承诺上使用 .then 不会像 .success 那样直接返回数据
            • 我完全按照上面的方法进行操作,但在控制器中出现错误“无法读取未定义的属性 'then'”。修复:完全删除 deferred/promise 并简单地 return $http(); 如第一条评论中所述
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-11-21
            • 1970-01-01
            相关资源
            最近更新 更多