AngularJS:OPTIONS preflight调用preceding一个$ http.post要求 [英] AngularJS: OPTIONS preflight call preceding a $http.post request

查看:285
本文介绍了AngularJS:OPTIONS preflight调用preceding一个$ http.post要求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用AngularJS V1.2.4。

我有角发送preflight OPTIONS调用的问题(Chrome的显示OPTIONS调用为取消),并解决它:

  $ httpProvider.defaults.useXDomain = TRUE;
删除$ httpProvider.defaults.headers.common ['X-要求-随着'];

这工作了我所有的资源$电话,一切都还不错。

现在我想实现身份验证,并且发送POST请求我与用户的凭证服务器的登录页面。我看到我正面临前的问题,而是$资源呼叫仍然正常工作。

什么是真正令人沮丧的是,这个问题发生的间歇性;我会改变周围的头几个选项,那么它会工作了一会儿,并停止没有任何code修改工作了。

我的服务器配置为CORS和正常工作与卷曲,和其他REST客户端。这里有一个例子:

 卷曲-X选项-ik的https://本地主机:3001 /身份验证-H来源:https://开头本地主机:8001
HTTP / 1.1 200 OK
内容类型:应用程序/ JSON的;字符集= UTF-8
内容长度:2
缓存控制:无缓存
访问控制允许来源:*
访问控制,最大年龄:86400
访问控制允许的方法:GET,HEAD,POST,PUT,DELETE,OPTIONS
访问控制 - 允许报头:授权,内容类型,如果 - 无 - 匹配,访问控制,允许报头,内容类型
访问控制展露报头:WWW身份验证,服务器授权
设置Cookie: session=Fe26.2**94705d49717d1273197ae86ce6661775627d7c6066547b757118c90c056e393b*2KYqhATojPoQhpB2OwhDwg*W9GsJjK-F-UPqIIHTBHHZx1RXipo0zvr97_LtTLMscRkKqLqr8H6WiGd2kczVwL5M25FBlB1su0JZllq2QB-9w**5510263d744a9d5dc879a89b314f6379d17a39610d70017d60acef01fa63ec10*pkC9zEOJTY_skGhb4corYRGkUNGJUr8m5O1US2YhaRE;安全;路径= /
日期:星期三,2013年12月18日23时35分56秒GMT
连接:保持活动

这里的$ http.post拨打:

  VAR authRequest = $ http.post(的https://+ $ location.host()+':3001 /身份验证',{电子邮件:电子邮件,密码:密码} );

当从我的应用程序工作的号召,这是OPTIONS请求的样子:

当它不工作,这是OPTIONS请求:

它看起来像头属性一大堆人失踪。有没有人遇到过类似的问题?

编辑:

只是为了澄清,当它不工作,请求其从未向服务器 - 这是在浏览器中立即中止

在Firebug中,请求头是:

 选项/验证HTTP / 1.1
主机:本地主机:3001
用户代理:Mozilla的/ 5.0(Macintosh上,英特尔的Mac OS X 10.8; RV:25.0)的Gecko / 20100101火狐/ 25.0
接受:text / html的,是application / xhtml + xml的,应用/ XML; Q = 0.9 * / *; Q = 0.8
接受语言: 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
接受编码:gzip,紧缩
产地:https://开头本地主机:8001
访问控制请求-方法:POST
访问控制请求报头:内容类型
代理授权:基本cGF0cmljZUB6b25nLmNvbTpjaGFuZ2VtZQ​​ ==
连接:保持活动
编译:无缓存
缓存控制:无缓存

更新:

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

下面是一些code:

  App.services.factory('AuthService',函数($ HTTP,$位置,$ Q){    VAR的currentUser;    返回{
        验证:功能(电子邮件,密码){            //承诺返回
            变种推迟= $ q.defer();            VAR authRequest = $ http.post('https://this.does.not.exist.com:3001/authenticate',{电子邮件:电子邮件,密码:密码});            authRequest.success(功能(数据,状态,头,配置){
                的currentUser =数据;
                的console.log('的currentUser服务设置为:);
                的console.log(的currentUser);
                //承诺的决心
                deferred.resolve();
            });            authRequest.error(功能(数据,状态,头,配置){
                的console.log('验证错误');
                的console.log(状态);
                的console.log(数据);
                的console.log(头);
                的console.log(配置);                //拒绝承诺
                deferred.reject('验证失败..');
            });            返回deferred.promise;
        },
        isAuthenticated:功能(){
            返回的currentUser ==未定义!;
        }
    };
});

和HTTP配置:

 的App.config(['$ httpProvider',函数($ httpProvider){    $ httpProvider.defaults.useXDomain = TRUE;
    //$httpProvider.defaults.headers.common = {};    的console.log('退出头');
    的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('结束登出头');    $ httpProvider.defaults.headers.common = {接受:应用/ JSON,纯文本/ * / *};
    $ httpProvider.defaults.headers.post = {内容类型:应用/ JSON的;字符集= UTF-8};    的console.log('后:注销头');
    的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('后:年底注销头');    $ httpProvider.interceptors.push(函数($位置$喷油器){
        返回{
            请求:功能(配置){                的console.log('的请求拦截!');                VAR PATH = $ location.path();
                的console.log('要求:'+路径);                //手动注入来解决循环依赖问题。
                变种AuthService = $ injector.get('AuthService');
                的console.log(AuthService);
                的console.log(配置);                如果(AuthService.isAuthenticated()及!&安培;!$ location.path()='/登录'){
                    的console.log('用户没有登录。');
                    $ location.path('/登录');
                }                //添加页眉
                的console.log(config.headers);
                返回配置;
            }
        };
    });
}]);


解决方案

这感觉就像它可能与你所打的其实是一个 HTTPS 端点上的本地主机。这意味着,你可能会使用某种自签名的SSL证书,这可能意味着浏览器认为不可信。

我第一次尝试直接到/验证端点,看看Chrome是否给你一个关于一个不受信任的证书的警告。看看是否接受该警告的作品。

否则,有可能当你在本地测试你可以打只是一个 HTTP 端点,看看是否能解决的事情?

I'm using AngularJS v1.2.4.

I had an issue with Angular sending a preflight OPTIONS call (Chrome was showing the OPTIONS call as 'canceled') and resolved it with:

$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];

That worked for all my $resource calls, and everything was good.

Now I'm trying to implementation authentication, and a login page that sends a POST request to my server with the user's credentials. I'm seeing the problem I was facing before, but $resource calls are still working fine.

What's really frustrating is that the problem happens intermittently; I'll change a few options surrounding the headers, then it'll work for a bit, and stop working again without any code change.

My server is configured for CORS and works fine with curl, and other REST clients. Here's an example:

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

Here's the $http.post call:

var authRequest = $http.post('https://' + $location.host() + ':3001/authenticate', {email: email, password: password});

When the call from my app works, this is how the OPTIONS request looks like:

When it doesn't work, this is the OPTIONS request:

It looks like a whole bunch of header attributes are missing. Has anyone encountered a similar issue?

Edit:

Just to clarify, when it doesn't work, the request never makes it to the server - it's instantly aborted in the browser.

In Firebug, the request headers are:

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

Update:

I've eliminated the possibly of a problem with the server, I think, by changing the host to a non-existent server. Still seeing the same behavior.

Here's some code:

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;
        }
    };
});

and HTTP Config:

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;
            }
        };
    });
}]);

解决方案

This feels like it might be related to the fact that you're hitting an https endpoint on your localhost. That means you're probably using some sort of self-signed SSL certificate, which may mean Chrome considers it untrusted.

I'd first try going directly to the /authenticate endpoint and see if Chrome gives you a warning about an untrusted certificate. See if accepting that warning works.

Otherwise, possibly while you're testing locally you can hit just an http endpoint and see if that solves things?

这篇关于AngularJS:OPTIONS preflight调用preceding一个$ http.post要求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆