Angular跨域请求CORS失败,但Node的http.get()成功返回

3
我正在尝试使用AngularJS访问API。我已经使用以下node代码检查了API的功能。这排除了故障原因。
var http = require("http");
url = 'http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10';

var request = http.get(url, function (response) {
    var buffer = ""
    response.on("data", function (chunk) {
        buffer += chunk;
    });
    response.on("end", function (err) {
        console.log(buffer);
        console.log("\n");
    });
});

我使用Node http-server运行我的Angular应用程序,参数如下:

"start": "http-server --cors -a localhost -p 8000 -c-1"

我的Angular控制器如下所示:

app.controller('Request', function($scope, $http){
    // functional URL = http://www.w3schools.com/website/Customers_JSON.php
    $scope.test = "functional";
    $scope.get = function(){

        $http.get('http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10',{
            params: {
                headers: {
                    //'Access-Control-Allow-Origin': '*'
                    'Access-Control-Request-Headers' : 'access-control-allow-origin'
                }
            }
        })
            .success(function(result) {
                console.log("Success", result);
                $scope.result = result;
            }).error(function() {
                console.log("error");
            });
        // the above is sending a GET request rather than an OPTIONS request
    };
});

控制器可以解析w3schools的URL,但是当传递asterank的URL时,它始终会返回CORS错误。

通过Firefox检查GET请求显示,标题没有被添加到GET请求。但除此之外,我不知道如何解决这个问题。对于正在学习Angular的人,希望得到帮助。

我尝试使用$http.jsonp()。GET请求成功执行(在网络上),但angular方法返回.error()函数。

var app = angular.module('sliderDemoApp', ['ngSlider', 'ngResource']);
    .config(function($httpProvider) {
        //Enable cross domain calls
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    });
4个回答

4
你需要明白一件简单的事情:尽管那些 http 模块看起来有些相似,但它们在CORS方面是完全不同的。实际上,node.js 的 http.get() 和 CORS 没有任何关系。它是你的服务器发出请求的方式,就像当你在浏览器地址栏中输入URL并打开它时一样。用户代理是不同的,但总体过程是相同的:客户端访问位于外部服务器上的页面。
现在注意与angular的 $http.get() 的区别:客户端打开一个运行脚本的页面,并尝试访问位于外部服务器上的页面。换句话说,这个请求在另一个页面的上下文中运行 - 位于其自己的域内。除非这个域被外部服务器允许在客户端代码中访问,否则就不可能 - 这正是CORS的目的。
有不同的解决方法:JSONP - 基本上意味着将响应包装到函数调用中 - 是一种可能的方式。但它有相同的关键点,就像其他解决方法一样 - 外部服务器应该允许这种通信方式。否则,你对JSONP的请求就会被忽略:服务器发送回常规JSON,这会在尝试将其处理为函数调用时导致错误。
底线是:除非外部服务器愿意在这个问题上合作,否则你将无法在客户端应用程序中使用它的数据 - 除非你通过你的服务器传递这些数据(这将充当代理)。

1
谢谢,这确实有助于澄清节点成功而角度无法访问它的机制。非常感谢你花时间详细说明区别。 - Stephen Fortune

1
Asterank现在允许跨域请求其API。您不再需要担心上述的解决方法。现在,一个简单的$http.get(http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10')就可以使用了,无需头文件。我上周给他们发了电子邮件,他们回复说已经配置了服务器以允许所有来源的请求。

Asterank的确切电子邮件响应:“我刚刚为Asterank启用了CORS(即Access-Control-Allow-Origin *)。希望这有所帮助!”


0

昨天我也遇到了CORS的类似问题,我使用了一个表单来解决它,希望这能有所帮助。

.config(function($httpProvider){
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
    $httpProvider.defaults.headers.common = {};
    $httpProvider.defaults.headers.post = {};
    $httpProvider.defaults.headers.put = {};
    $httpProvider.defaults.headers.patch = {};
})

.controller('FormCtrl', function ($scope, $http) {
        $scope.data = {
            q: "test"//,
//            z: "xxx"
        };

        $scope.submitForm = function () {
            var filters = $scope.data;
            var queryString ='';
            for (i in filters){
                queryString=queryString + i+"=" + filters[i] + "&";
            }
            $http.defaults.useXDomain = true;
            var getData = {
                method: 'GET',
                url: 'https://YOUSEARCHDOMAIN/2013-01-01/search?' + queryString,
                headers: {
                    'Content-Type': 'application/json; charset=utf-8'
                }
            };
            console.log("posting data....");
            $http(getData).success(function(data, status, headers, config) {
                console.log(data);
            }).error(function(data, status, headers, config) {
            });
        }
    })

    <div ng-controller="FormCtrl">
        <form  ng-submit="submitForm()">
            First names:   <input type="text" name="form.firstname"> 
            Email Address: <input type="text" ng-model="form.emailaddress">
            <button>bmyutton</button>
        </form>
    </div>

似乎也可以使用您上面发布的URL。

ObjectA: 0.017DEC: 50.2413KMAG: 10.961KOI: 72.01MSTAR: 1.03PER: 0.8374903RA: 19.04529ROW: 31RPLANET: 1.38RSTAR: 1T0: 64.57439TPLANET: 1903TSTAR: 5627UPER: 0.0000015UT0: 0.00026

我还应该补充一点,在Chrome中,您需要CORS插件。对于Angular,我没有深入研究这个问题。我发现一个基本的HTML可以绕过这些CORS限制,这只是一个解决方法,直到我有更多时间来了解这个问题。


表单不是解决方法:除非安装并激活您提到的插件,否则您将遇到相同的问题。 - raina77ow
可以确认我添加了你提到的插件,我的代码可以正常工作,而不需要使用表单解决方法,这个插件确实起到了魔法般的作用。在实施必要的后端之前,这绝对是一个有用的技巧。 - Stephen Fortune

0

经过大量的搜索,我发现解决这个问题的最佳本地方案是npm模块CORS-anywhere。我使用它创建了AngularJS AWS Cloudsearch Demo


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接