6

这已经通过 Stackoverflow 进行了讨论,但我一直无法找到解决方案来使其正常工作。我什至尝试关注这篇文章中讨论的很多内容(CORS.Flask <-> AngularJS的问题),因为它与我的设置密切相关,但我仍然很迷茫。

我有一个在本地运行的 python flask api 服务器。我已将此域命名为 bac-api。这是这个虚拟主机的样子。

<VirtualHost *:80>
    ServerName bac-api

    WSGIDaemonProcess bacapi python-path=/home/lumberjacked/workspace/bas/development/lib/python2.7/site-packages
    WSGIScriptAlias / /home/lumberjacked/workspace/bas/development/bac-api/bacapi.wsgi
    Header set Access-Control-Allow-Origin "*"
    Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, application/json"
    Header set Access-Control-Allow-Methods "POST, GET, OPTIONS"

    <Directory /home/lumberjacked/workspace/bas/development/bac-api>
        WSGIProcessGroup bacapi
        WSGIApplicationGroup %{GLOBAL}
        Order deny,allow
        Allow from all
    </Directory>

#SSLEngine on
#SSLCertificateFile /etc/apache2/ssl/bac_api_ssl.crt
#SSLCertificateKeyFile /etc/apache2/ssl/bac_api_ssl.key
</VirtualHost>

我有一个 angularjs 站点作为我的前端在一个名为 manage.bac 的单独域上运行。我正在编写一个连接到 bac-api 的身份验证服务,并发布一个 api 密钥和/或用户凭据,询问服务器用户是否经过身份验证。

我可以蜷缩到服务器上,这可以正常工作并返回响应。

curl -X POST -H "Content-Type: application/json" -d '{ "api": "7f3d6d7338b921ae4ca95cecc452ef1790005ec10c2343fabe5a59ea" }' http://bac-api/authenticated/  

response -- {"authenticated": false}

还要去 manage.bac 并放置我的登录信用 email@email.com 和密码,我会得到相同的响应,但如果您未使用存储的会话进行身份验证,我已将其配置为返回 401。

POST http://bac-api/authenticated/ 401 (UNAUTHORIZED) bac-api/authenticated/:1

当我切换到 ssl 证书和端口 443 时,问题就开始了。因此,如果在两个域上,我将 vhost 切换到端口 443 并取消注释 ssl 证书。重新启动 apache 后没有错误,并且域工作,只要不显示任何类型的 500 错误或类似的东西。我可以使用 https 转到 bac-api 服务器并获得响应。

curl -k -X POST -H "Content-Type: application/json" -d '{ "api": "7f3d6d7338b921ae4ca95cecc452ef1790005ec10c2343fabe5a59ea" }' https://bac-api/authenticated/

response -- {"authenticated": false}

但是只要我去https://manage.bac并重定向到登录页面,所有的麻烦似乎都开始了。

一旦我在登录字段中单击,控制台就会抛出此错误,我不知道它是否相关。

Blocked a frame with origin "https://manage.bac" from accessing a frame with origin "chrome-extension://hdokiejnpimakedhajhdlcegeplioahd".  The frame requesting access has a protocol of "https", the frame being accessed has a protocol of "chrome-extension". Protocols must match.

这是我的 angularjs 身份验证代码,其中 console.log 方法输出了一些东西。

$http.post('https://bac-api/login/', user)
            .success( function( user ) {
                console.log('success');
                console.log(user);                     
            })
            .error( function( error ) {
                console.log('error');
                console.log(error);
            });

Object {email: "email@email.com", password: "password"} authentication-service.js:36
error authentication-service.js:50
                  authentication-service.js:51

当此错误再次出现时,响应中根本没有任何内容。我可以在 chrome 工具的网络选项卡中看到,这个请求正在被预先发送,因为它正在向服务器发送一个 OPTIONS。

OPTIONS /login/ HTTP/1.1
Host: bac-api
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: https://manage.bac
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-requested-with
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

我还可以在“网络”选项卡中看到它显示为 OPTIONS 并且已被取消。我不知道那是什么意思。

在此处输入图像描述

我已经在 angularjs 中配置了这些选项,但它似乎对任何事情都没有影响。

config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];

    }
]);

同样在我的烧瓶应用程序中尝试实现这里提到的装饰器http://flask.pocoo.org/snippets/56/并且在其他stackoverflow帖子中也提到过。这似乎也没有任何作用。我还假设因为我在我的虚拟主机中放入了 api 服务器的访问标头,所以我真的不需要在应用程序中做同样的事情。尽管我可能完全错了,因为我不知道自己在做什么。

非常感谢任何帮助。如果这似乎是一个重复的问题,我很抱歉,但到目前为止我无法让它工作,我已经尝试了 stackoverflow 上的每一篇文章,我可以解决这个问题。

--- 使用更新的信息进行编辑

今天早上作为一个实验,我将两个虚拟主机切换回端口 80 并注释掉所有允许访问标头。重新启动并尝试再次登录,这是我的结果。

Failed to load resource: Origin http://manage.bac is not allowed by Access-Control-Allow-Origin. http://bac-api/authenticated/
XMLHttpRequest cannot load http://bac-api/authenticated/. Origin http://manage.bac is not allowed by Access-Control-Allow-Origin. manage.bac/:1

所以在这个错误之后,我进入了我的 bac-api vhost 和未注释的 Header 设置 Access-Control-Allow-Origin "*" 并重新启动并尝试登录。这是显示的新错误。

OPTIONS http://bac-api/authenticated/ Request header field Content-Type is not allowed  by Access-Control-Allow-Headers. angular.js:9312
(anonymous function) angular.js:9312
sendReq angular.js:9146
$http angular.js:8937
Authenticator.isLoggedIn authentication-service.js:13
RouteConfig.login.resolve.Auth state-service-provider.js:16
invoke angular.js:2902
(anonymous function) angular-ui-router.js:801
forEach angular.js:137
resolve angular-ui-router.js:797
resolveState angular-ui-router.js:813
transitionTo angular-ui-router.js:704
(anonymous function) angular-ui-router.js:615
invoke angular.js:2902
handleIfMatch angular-ui-router.js:433
rule angular-ui-router.js:452
update angular-ui-router.js:487
Scope.$broadcast angular.js:8307
afterLocationChange angular.js:5649
(anonymous function) angular.js:5637
Scope.$eval angular.js:8057
Scope.$digest angular.js:7922
Scope.$apply angular.js:8143
(anonymous function) angular.js:981
invoke angular.js:2895
resumeBootstrapInternal angular.js:979
bootstrap angular.js:993
angularInit angular.js:954
(anonymous function) angular.js:14843
c jquery-1.10.1.min.js:4
p.fireWith jquery-1.10.1.min.js:4
x.extend.ready jquery-1.10.1.min.js:4
q jquery-1.10.1.min.js:4
XMLHttpRequest cannot load http://bac-api/authenticated/. Request header field Content- Type is not allowed by Access-Control-Allow-Headers. manage.bac/:1

因此,为了解决这个错误并允许 Content-Type 通过我回到我的 bac-api vhost 并添加回 Header set Access-Control-Allow-Headers“Content-Type”。在页面加载时重新开始浏览到 manage.bac 后,这些结果如下所示。

POST http://bac-api/authenticated/ 401 (UNAUTHORIZED) bac-api/authenticated/:1

这很好,因为这意味着我收到了 {"authenticated": false} 响应,它发回了未经授权的 401。如果我继续并尝试登录,我会得到这些结果。

Object {email: "email@email.com", password: "password"} authentication-service.js:36
success authentication-service.js:40
Object {login: false} authentication-service.js:41

这也有效。这是产生此输出的 angularjs 代码。

$http.post('http://bac-api/login/', user)
            .success( function( user ) {
                console.log('success');
                console.log(user);                    
            })
            .error( function( error ) {
                console.log('error');
                console.log(error);
            });

现在我的想法很棒,如果它在端口 80 上工作,我现在可以将它切换到端口 443 并继续滚动。因此,我将 vhosts 切换到端口 443 并再次浏览到 manage.bac 以登录。在尝试登录之前的页面加载中,我得到了这些结果。

在此处输入图像描述

再次,当我尝试登录并提交表单时,我也得到了这些结果。

Object {email: "email@email.com", password: "password"} authentication-service.js:36
error authentication-service.js:50
         authentication-service.js:51

也在网络选项卡上 在此处输入图像描述

这只是为了尝试为每个人提供更多信息,以帮助我找到此问题的原因。

----- 再次编辑更多信息

今晚我开始尝试使用 curl 进行测试,看看哪些标头会通过 OPTIONS 请求返回

这是我直接从“网络”选项卡中复制的 curl 请求,假设这与 angularjs 发送的 OPTIONS 请求相同。首先我会从网络选项卡中放置 OPTIONS 请求,然后是我的 curl 请求。

OPTIONS https://bac-api/login/ HTTP/1.1
Access-Control-Request-Method: POST
Origin: https://manage.bac
Referer: https://manage.bac/
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)    Chrome/29.0.1547.76 Safari/537.36
Access-Control-Request-Headers: accept, origin, x-requested-with, content-type

curl -i -k -X OPTIONS -H "Access-Control-Request-Method: POST" -H "Origin: https://manage.bac" -H "Referer: https://manage.bac/" -H "Access-Control-Request-Headers: accept, origin, content-type" https://bac-api/login/

这是 curl 的回复

HTTP/1.1 200 OK
Date: Tue, 01 Oct 2013 02:51:17 GMT
Server: Apache/2.2.22 (Ubuntu)
Allow: POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Max-Age: 21600
Content-Length: 0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods: POST, GET, OPTIONS
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8 

这似乎表明服务器配置正确并使用正确的标头响应 OPTIONS 请求。但是,正如我在上面的图片中发布的那样,当我在浏览器中仍然在“网络”选项卡上运行它时,它被取消了,并且错误响应中没有任何内容返回。

4

1 回答 1

4

我能够解决这个问题,这是最愚蠢的事情。我将挖掘其他帮助我找到解决方案的 stackoverflow 帖子。但基本上在测试期间,我生成了自签名证书以在本地使用。显然,如果在跨域发布时不信任证书,firefox 和 chrome 都会自动取消您的请求。在他们停止取消请求之前,我必须同时进入 chrome 和 firefox 以添加证书并将它们标记为受信任。现在一切正常。

同样在这次调查中,我发现您不需要将请求助手添加到 Flask 中,以将标头添加到您的响应和 Apache 配置中。如果你把它们都放在里面,它会同时添加标题。在我的配置中,我选择将它添加到我的 Apache 配置中,因为它使我的 python 代码更干净。

于 2013-10-18T18:43:19.850 回答