如何在 AngularJS 中正确使用 HTTP.GET?具体来说,对于外部 API 调用?

Posted

技术标签:

【中文标题】如何在 AngularJS 中正确使用 HTTP.GET?具体来说,对于外部 API 调用?【英文标题】:How to use HTTP.GET in AngularJS correctly? In specific, for an external API call? 【发布时间】: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 相关问题上犯了一个错误。你能指点我打这个电话的正确方法吗?非常感谢!

【问题讨论】:

这是一个超级常见的问题:) 【参考方案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(); 如第一条评论中所述

以上是关于如何在 AngularJS 中正确使用 HTTP.GET?具体来说,对于外部 API 调用?的主要内容,如果未能解决你的问题,请参考以下文章

Angularjs 如何对 $http 调用进行正确的错误处理?

如何在 AngularJS 中插入命令或阻止 $http 的 JSONP 自动解析?

angularjs拦截器:为啥在$http拦截器中没有收到正确的状态码和消息

当我使用 CORS 时,AngularJS $http 似乎没有正确响应

AngularJS:绑定到服务属性的正确方法

AngularJs,如何发送 $http 的参数 [重复]