apache - 使用在单独的域上运行Flask api和Angularjs前端的Apache正确配置Angularjs和CORS

标签 apache angularjs flask cors

整个Stackoverflow都对此进行了讨论,但是我无法找到使它起作用的解决方案。我什至尝试遵循这篇博文(Issues with 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 key 和/或用户凭据,询问服务器是否对用户进行了身份验证。

我可以 curl 到服务器,这可以工作并返回响应。
curl -X POST -H "Content-Type: application/json" -d '{ "api": "7f3d6d7338b921ae4ca95cecc452ef1790005ec10c2343fabe5a59ea" }' http://bac-api/authenticated/  

response -- {"authenticated": false}

同样要去manage.bac并放置我的登录信用凭证email@email.com和密码,我得到相同的响应,但是如果您未通过存储 session 进行身份验证,我也将其配置为返回401。
POST http://bac-api/authenticated/ 401 (UNAUTHORIZED) bac-api/authenticated/:1

当我切换到ssl证书和端口443时,问题就开始了。因此,如果在两个域上,我都将虚拟主机切换到端口443,并取消对ssl证书的注释。重新启动apache之后,没有错误,并且域可以正常工作,直到不显示任何500错误或类似的错误。我可以使用https curl 到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

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

我已经在我的angularjs中配置了这些选项,但是似乎没有任何区别。
config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];

    }
]);

同样在我的flask应用程序内部,尝试实现这里http://flask.pocoo.org/snippets/56/和其他stackoverflow帖子中提到的装饰器。这似乎也不起作用。我还假设,因为我将虚拟主机放入了api服务器的访问 header ,所以我实际上不需要在应用程序中执行相同的操作。虽然我可能完全错了,因为我对正在做的事情一无所知。

任何帮助,我们真的很感激。很抱歉,如果这似乎是一个重复的问题,但是到目前为止,我无法解决这个问题,并且我已经尝试过关于stackoverflow的每篇文章,我可以解决该问题。

---编辑更新的信息

今天上午作为实验,我将两个虚拟主机都切换回了端口80,并注释掉了所有“允许访问” header 。重新启动并尝试再次登录,这是我的结果。
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虚拟主机,并且未注释的 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虚拟主机,然后添加Header集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并继续滚动。因此,我将虚拟主机切换到端口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请求返回了哪些 header

这是我将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 

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

最佳答案

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

同样在此调查中,我发现您不需要将Flask的请求助手添加到Flask中,即可将 header 添加到响应和Apache配置中。如果将它们放在两者中,它将两次都添加 header 。在我的配置中,我选择将其添加到我的Apache配置中,因为它使我的python代码更加干净。

关于apache - 使用在单独的域上运行Flask api和Angularjs前端的Apache正确配置Angularjs和CORS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19086365/

相关文章:

javascript - 样式化 HTML 选择/选项元素

flask - 如何等待传递给 Flask-SocketIO 的 emit() 的回调?

javascript - 在Python中将二进制字符串解释为图像,由Javascript native 方法生成

c# - 在缺少 setup.py 的 Windows 上构建 Apache QPID

ruby-on-rails - Rails + Passenger + Apache + Alias

apache - Xampp Apache 未启动 SSL 配置

javascript - 单元测试以确保函数调用 api 并将数据分配给变量

php - 如何将可扩展的长轮询服务器与 PHP 集成?

javascript - 过滤 ng-options

python - wtforms,动态添加类到表单