AngularJS:在 $http.post 请求之前的 OPTIONS 预检调用

AngularJS: OPTIONS preflight call preceding a $http.post request(AngularJS:在 $http.post 请求之前的 OPTIONS 预检调用)

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

问题描述

我正在使用 AngularJS v1.2.4.

I'm using AngularJS v1.2.4.

我在 Angular 发送预检 OPTIONS 调用时遇到问题(Chrome 将 OPTIONS 调用显示为已取消")并通过以下方式解决:

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'];

这对我所有的 $resource 调用都有效,一切都很好.

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

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

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.

我的服务器针对 CORS 进行了配置,并且可以与 curl 和其他 REST 客户端一起正常工作.这是一个例子:

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

这是 $http.post 调用:

Here's the $http.post call:

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

当我的应用调用有效时,OPTIONS 请求如下所示:

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

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

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?

澄清一下,当它不起作用时,请求永远不会到达服务器 - 它会立即在浏览器中中止.

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

在 Firebug 中,请求标头是:

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

更新:

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

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.

这里有一些代码:

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 认为它不受信任.

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.

我首先尝试直接访问/authenticate 端点,看看 Chrome 是否会向您发出有关不受信任的证书的警告.看看接受该警告是否有效.

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.

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

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

这篇关于AngularJS:在 $http.post 请求之前的 OPTIONS 预检调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:AngularJS:在 $http.post 请求之前的 OPTIONS 预检调用

基础教程推荐