Javascript AngularJS:OPTIONS在$http.post请求之前的飞行前调用

Javascript AngularJS:OPTIONS在$http.post请求之前的飞行前调用,javascript,http,angularjs,cors,Javascript,Http,Angularjs,Cors,我正在使用AngularJSV1.2.4 我在发送飞行前选项呼叫时遇到问题(Chrome显示选项呼叫为“已取消”),并通过以下方式解决了此问题: $httpProvider.defaults.useXDomain = true; delete $httpProvider.defaults.headers.common['X-Requested-With']; 这适用于我所有的$resource调用,一切都很好 现在,我尝试实现身份验证,并创建一个登录页面,该页面使用用户凭据向我的服务器发送PO

我正在使用AngularJSV1.2.4

我在发送飞行前选项呼叫时遇到问题(Chrome显示选项呼叫为“已取消”),并通过以下方式解决了此问题:

$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
这适用于我所有的$resource调用,一切都很好

现在,我尝试实现身份验证,并创建一个登录页面,该页面使用用户凭据向我的服务器发送POST请求。我看到了我以前面临的问题,但是$resource调用仍然可以正常工作

真正令人沮丧的是,问题间歇性地发生;我将更改标题周围的一些选项,然后它将工作一段时间,并在不更改任何代码的情况下再次停止工作

我的服务器是为CORS配置的,可以与curl和其他REST客户机配合使用。下面是一个例子:

curl -X OPTIONS -ik 'https://localhost:3001/authenticate' -H "Origin: https://localhost:8001"
HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
content-length: 2
cache-control: no-cache
access-control-allow-origin: *
access-control-max-age: 86400
access-control-allow-methods: GET, HEAD, POST, PUT, DELETE, OPTIONS
access-control-allow-headers: Authorization, Content-Type, If-None-Match, Access-Control-Allow-Headers, Content-Type
access-control-expose-headers: WWW-Authenticate, Server-Authorization
set-cookie: session=Fe26.2**94705d49717d1273197ae86ce6661775627d7c6066547b757118c90c056e393b*2KYqhATojPoQhpB2OwhDwg*W9GsJjK-F-UPqIIHTBHHZx1RXipo0zvr97_LtTLMscRkKqLqr8H6WiGd2kczVwL5M25FBlB1su0JZllq2QB-9w**5510263d744a9d5dc879a89b314f6379d17a39610d70017d60acef01fa63ec10*pkC9zEOJTY_skGhb4corYRGkUNGJUr8m5O1US2YhaRE; Secure; Path=/
Date: Wed, 18 Dec 2013 23:35:56 GMT
Connection: keep-alive
下面是$http.post调用:

var authRequest = $http.post('https://' + $location.host() + ':3001/authenticate', {email: email, password: password});
当来自我的应用程序的呼叫起作用时,选项请求是这样的:

当它不起作用时,这是选项请求:

看起来缺少了一大堆标题属性。有没有人遇到过类似的问题

编辑:

只是澄清一下,当它不工作时,请求永远不会发送到服务器——它会在浏览器中立即中止

在Firebug中,请求头是:

OPTIONS /authenticate HTTP/1.1
Host: localhost:3001
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:25.0) Gecko/20100101 Firefox/25.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.91,en-GB;q=0.82,fr-FR;q=0.73,fr;q=0.64,utf-8;q=0.55,utf;q=0.45,de-DE;q=0.36,de;q=0.27,en-sg;q=0.18,en-ca;q=0.09
Accept-Encoding: gzip, deflate
Origin: https://localhost:8001
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Proxy-Authorization: Basic cGF0cmljZUB6b25nLmNvbTpjaGFuZ2VtZQ==
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

更新:

我认为,通过将主机更改为不存在的服务器,我已经消除了服务器可能出现的问题。仍然看到同样的行为

下面是一些代码:

App.services.factory('AuthService', function ($http, $location, $q) {

    var currentUser;

    return {
        authenticate: function (email, password) {

            //promise to return
            var deferred = $q.defer();

            var authRequest = $http.post('https://this.does.not.exist.com:3001/authenticate', {email: email, password: password});

            authRequest.success(function (data, status, header, config) {
                currentUser = data;
                console.log('currentUser in service set to:');
                console.log(currentUser);
                //resolve promise
                deferred.resolve();
            });

            authRequest.error(function (data, status, header, config) {
                console.log('authentication error');
                console.log(status);
                console.log(data);
                console.log(header);
                console.log(config);

                //reject promise
                deferred.reject('authentication failed..');
            });

            return deferred.promise;
        },
        isAuthenticated: function () {
            return currentUser !== undefined;
        }
    };
});
和HTTP配置:

App.config(['$httpProvider', function ($httpProvider) {

    $httpProvider.defaults.useXDomain = true;
    //$httpProvider.defaults.headers.common = {};

    console.log('logging out headers');
    console.log($httpProvider.defaults);
    console.log($httpProvider.defaults.headers.common);
    console.log($httpProvider.defaults.headers.post);
    console.log($httpProvider.defaults.headers.put);
    console.log($httpProvider.defaults.headers.patch);
    console.log('end logging out headers');

    $httpProvider.defaults.headers.common = {Accept: "application/json, text/plain, */*"};
    $httpProvider.defaults.headers.post = {"Content-Type": "application/json;charset=utf-8"};

    console.log('after: logging out headers');
    console.log($httpProvider.defaults.headers.common);
    console.log($httpProvider.defaults.headers.post);
    console.log($httpProvider.defaults.headers.put);
    console.log($httpProvider.defaults.headers.patch);
    console.log('after: end logging out headers');

    $httpProvider.interceptors.push(function ($location, $injector) {
        return {
            'request': function (config) {

                console.log('in request interceptor!');

                var path = $location.path();
                console.log('request: ' + path);

                //injected manually to get around circular dependency problem.
                var AuthService = $injector.get('AuthService');
                console.log(AuthService);
                console.log(config);

                if (!AuthService.isAuthenticated() && $location.path() != '/login') {
                    console.log('user is not logged in.');
                    $location.path('/login');
                }

                //add headers
                console.log(config.headers);
                return config;
            }
        };
    });
}]);

这感觉可能与您在本地主机上访问
https
端点有关。这意味着您可能正在使用某种自签名SSL证书,这可能意味着Chrome认为它不可信

我首先尝试直接转到/authenticate端点,看看Chrome是否会对不受信任的证书发出警告。看看接受这个警告是否有效


否则,当您在本地进行测试时,您可能只需点击一个
http
端点,看看这是否解决了问题?

非常感谢Michael Cox。我接受他的回答,因为这让我找到了解决方案,但这里有更多的细节:

调查https问题,我发现:

但我的问题略有不同。在我按照上面链接中的说明操作之后,它仍然不起作用。我仔细阅读了chrome的“untrusted”消息,它有点像“你试图访问mylocalhost.com,但服务器将自己表示为”


事实证明,我匆忙创建的自签名证书是“server.crt”,而它应该是“mylocalhost.crt”

您不能将
允许凭据与
访问控制允许源代码一起使用:

重要注意事项:当响应认证请求时,服务器必须指定域,并且不能使用通配符

关于GET请求,如果它们没有特殊的头,则不需要飞行前等


来源:。(网络上最好的CORS链接!)

您确定您的脚本/应用程序没有发送双重请求吗?同步(表单提交)+异步请求到同一url?@asumaran您能澄清一下吗?我很确定这只是一个请求。使用firebug调试CORS问题。Chrome有一个已知问题,不会显示所有可用信息@在萤火虫身上也有同样的东西。我编辑了我的问题以反映这一点。嘿,迈克尔,谢谢你的回答!HTTPS问题可能存在,但我也在使用应用程序其他部分中的$resource对象访问HTTPS端点(在同一台服务器上),并且似乎一切正常。不管怎样,明天早上我会试试你的建议。我访问了Chrome中的“/authenticate”端点,没有关于不可信证书的警告;在这之前的某个时候,当我第一次开始开发应用程序时,我可能已经接受了它。另外,当我改为调用$http.get,并在服务器上有一个相应的get/authenticate端点时,它似乎工作得很好。我在我的$resources中观察到了相同的行为。因为您从localhost(至少)发送POST或PUT请求,所以Chrome从选项请求开始。我不知道为什么(以前可能会执行一些安全控制),但这就是它的工作方式。