Python Flask Google App Engine允许Access-Control-Allow-Origin跨域访问

最近在做一个纯API接口,部署到Google App Engine上面(为了利用GAE的负载均衡,减少服务器压力)。

最后在另外一台服务器上调用的时候,却无法正确获取数据,提示错误如下:

1
XMLHttpRequest cannot load '<some-url>'. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '<my-url>' is therefore not allowed access.

经过搜索发现是因为跨域调用问题(即从一个域名请求另外一个域名下的信息,至少在Chrome中是禁止的)

解决该问题的方法如错误提示信息所示,在服务器端的response加入Access-Control-Allow-Origin即可。

网上查出来的很多方法都是通过在GAE的app.yaml文件里面添加来实现的,后面我尝试后发现不管用。

于是经过一番搜索,搜索出了这个:Decorator for the HTTP Access Control

为Flask写一个访问修饰器,然后,通过在要控制Access-Control的路由函数前面添加@crossdomain(origin=’*’)来实现发送Access-Control-Allow-Origin头。

首先,我们定义一个如下函数(这个函数内部还有函数哦):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from datetime import timedelta
from flask import make_response, request, current_app
from functools import update_wrapper

def crossdomain(origin=None, methods=None, headers=None,
max_age=21600, attach_to_all=True,
automatic_options=True):
if methods is not None:
methods = ', '.join(sorted(x.upper() for x in methods))
if headers is not None and not isinstance(headers, basestring):
headers = ', '.join(x.upper() for x in headers)
if not isinstance(origin, basestring):
origin = ', '.join(origin)
if isinstance(max_age, timedelta):
max_age = max_age.total_seconds()

def get_methods():
if methods is not None:
return methods

options_resp = current_app.make_default_options_response()
return options_resp.headers['allow']

def decorator(f):
def wrapped_function(*args, **kwargs):
if automatic_options and request.method == 'OPTIONS':
resp = current_app.make_default_options_response()
else:
resp = make_response(f(*args, **kwargs))
if not attach_to_all and request.method != 'OPTIONS':
return resp

h = resp.headers

h['Access-Control-Allow-Origin'] = origin
h['Access-Control-Allow-Methods'] = get_methods()
h['Access-Control-Max-Age'] = str(max_age)
if headers is not None:
h['Access-Control-Allow-Headers'] = headers
return resp

f.provide_automatic_options = False
return update_wrapper(wrapped_function, f)
return decorator

接着,我们只需要在我们要加入Access-Control-Allow-Origin头的位置添加下面这一句即可:

1
2
3
4
5
6
7
8
#
@crossdomain(origin='*') # <-添加这句,可以把*改为想要允许的域名

#
@app.route('/my_service')
@crossdomain(origin='*') #这货的添加位置应该在路由之后
def my_service():
#do something

然后,我们再次调用API,就会发现,没有报这个错误了。

0%