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

lum*_*ked 6 apache cors flask angularjs

这已经通过Stackoverflow进行了讨论,但我无法找到使其工作的解决方案.我甚至尝试过这篇文章中讨论的很多内容(CORS问题.烧瓶< - > AngularJS),因为它与我的设置完全相关,但我仍然很丢失.

我有一个本地运行的python flask api服务器.我已将此域名命名为bac-api.这是vhost的样子.

<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>
Run Code Online (Sandbox Code Playgroud)

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

我可以卷曲到服务器,这可以工作并返回一个响应.

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

response -- {"authenticated": false}
Run Code Online (Sandbox Code Playgroud)

还要管理.bac和我的登录信用卡email@email.com和密码我得到相同的响应,但我已经配置它返回401如果您没有使用存储的会话进行身份验证.

POST http://bac-api/authenticated/ 401 (UNAUTHORIZED) bac-api/authenticated/:1
Run Code Online (Sandbox Code Playgroud)

当我切换到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}
Run Code Online (Sandbox Code Playgroud)

但是一旦我转到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.
Run Code Online (Sandbox Code Playgroud)

这是我的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
Run Code Online (Sandbox Code Playgroud)

当此错误返回时,响应中根本没有任何内容.我可以在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
Run Code Online (Sandbox Code Playgroud)

我也可以在网络选项卡中看到它显示为OPTIONS并且已被取消.我不知道这意味着什么.

在此输入图像描述

我已经使用这些选项配置了angularjs内部,但似乎没有任何区别.

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

    }
]);
Run Code Online (Sandbox Code Playgroud)

在我的烧瓶应用程序内部尝试实现这里提到的装饰器http://flask.pocoo.org/snippets/56/,并在其他stackoverflow帖子中也提到过.这似乎也没有做任何事情.另外我假设因为我在我的vhost中放入了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
Run Code Online (Sandbox Code Playgroud)

所以在这个错误之后我进入了我的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
Run Code Online (Sandbox Code Playgroud)

因此,要解决此错误并允许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
Run Code Online (Sandbox Code Playgroud)

这是好事,因为这意味着我收到了一个{"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
Run Code Online (Sandbox Code Playgroud)

这也有效.这是生成此输出的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);
            });
Run Code Online (Sandbox Code Playgroud)

现在我的想法很棒,如果它在端口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
Run Code Online (Sandbox Code Playgroud)

还有网络标签 在此输入图像描述

这只是试图给每个人提供更多信息,帮助我找到解决这个问题的原因.

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

今晚我开始尝试用curl测试这个,看看有什么标题回来了OPTIONS请求

这是我直接从网络选项卡中复制它的卷曲请求,假设这是与angularjs发送的OPTIONS请求相同.First Ill从网络选项卡中输出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/
Run Code Online (Sandbox Code Playgroud)

这是卷曲的回应

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 
Run Code Online (Sandbox Code Playgroud)

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

lum*_*ked 3

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

另外,在这次调查中,我发现您不需要将请求帮助程序添加到 Flask 中来将标头添加到您的响应和 Apache 配置中。如果您将它们都放入其中,则会两次添加标题。在我的配置中,我选择将其添加到我的 Apache 配置中,因为它使我的 python 代码更加清晰。