45

我使用 Flask Restful 开发了一个小型的只写 REST api,它接受来自少数可能具有更改 IP 地址的客户端的 PUT 请求。我的客户是运行 AngularJS 前端的嵌入式 Chromium 客户端;他们使用一个简单的魔法密钥对我的 API 进行身份验证——这对于我非常有限的规模来说已经足够了。

我现在正在测试部署我的 API,我注意到 Angular 客户端正在尝试向我的 Flask 服务发送一个 OPTIONS http 方法。与此同时,我的 API 正在回复 404(因为我还没有编写 OPTIONS 处理程序,只有一个 PUT 处理程序)。似乎在发送不是 POST 或 GET 的跨域请求时,Angular 会在服务器发送一个 pre-flight OPTIONS 方法,以确保在发送实际请求之前跨域请求被接受。那正确吗?

无论如何,我如何允许所有跨域 PUT 请求到 Flask Restful API?我之前使用过带有(非 RESTful)Flask 实例的跨域装饰器,但是我是否需要在我的 API 中也编写一个 OPTIONS 处理程序?

4

9 回答 9

61

使用Flask-CORS模块,您可以在不更改代码的情况下进行跨域请求。

from flask.ext.cors import CORS

app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})

更新

正如Eric建议的那样,该flask.ext.cors模块现在已被弃用,您应该使用以下代码:

from flask_cors import CORS

app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
于 2014-12-11T13:23:16.217 回答
35

您可以使用 after_request 挂钩:

@app.after_request
def after_request(响应):
    response.headers.add('Access-Control-Allow-Origin', '*')
    response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
    response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
    返回响应
于 2015-03-08T04:41:26.357 回答
21

我通过重写我的 Flask 后端以在我的 PUT 响应中使用 Access-Control-Allow-Origin 标头回答来解决了这个问题。此外,我在我的 Flask 应用程序中创建了一个 OPTIONS 处理程序,以按照我在 http RFC 中阅读的内容来回答选项方法。

PUT 方法的返回如下所示:

return restful.request.form, 201, {'Access-Control-Allow-Origin': '*'} 

我的 OPTIONS 方法处理程序如下所示:

def options (self):
    return {'Allow' : 'PUT' }, 200, \
    { 'Access-Control-Allow-Origin': '*', \
      'Access-Control-Allow-Methods' : 'PUT,GET' }

@tbicr 是对的:Flask 会自动为您回答 OPTIONS 方法。但是,在我的情况下,它没有传输带有该答案的 Access-Control-Allow-Origin 标头,因此我的浏览器从 api 获得了似乎暗示不允许跨域请求的回复。在我的案例中,我重载了选项请求并添加了 ACAO 标头,浏览器似乎对此感到满意,并在 OPTIONS 后面加上一个也可以工作的 PUT。

于 2013-11-14T15:24:16.623 回答
9

这个解决方法怎么样:

from flask import Flask
from flask.ext import restful
from flask.ext.restful import Api
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config.from_object('config')

#flask-sqlalchemy
db = SQLAlchemy(app)

#flask-restful
api = restful.Api(app)

@app.after_request

def after_request(response):
  response.headers.add('Access-Control-Allow-Origin', '*')
  response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
  response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
  return response

import views

我从教程中获取了这个。效果很好。实际上,我认为这是迄今为止我见过的最好的方法。

在每个端点上返回{'Access-Control-Allow-Origin': '*'}似乎效率不高,因为您必须在每个端点上添加它。有点讨厌......,至少对我来说。

我试过@cors.crossdomain(origin='*')了,但看起来它只适用于GET请求。

于 2016-06-09T19:34:11.490 回答
5

只是对此评论的更新。Flask CORS 是要走的路,但不推荐使用 flask.ext.cors。

利用: from flask_cors import CORS

于 2017-11-14T14:45:28.310 回答
4

你是对的,OPTIONS每次在浏览器中真正请求之前调用的方法。OPTIONS响应具有允许的方法和标头。Flask 自动处理OPTIONS请求。

要获得跨域请求的访问权限,您的 API 必须具有Access-Control-Allow-Origin标头。它可以包含特定的域,但如果您想允许来自任何域的请求,您可以将其设置为Access-Control-Allow-Origin: *.

要为您设置 CORS,flask可以查看一个扩展代码或尝试使用此扩展:https ://github.com/wcdolphin/flask-cors/blob/master/flask_cors.py 。

要设置 CORS 以flask-restful查看此拉取请求:https ://github.com/twilio/flask-restful/pull/122和https://github.com/twilio/flask-restful/pull/131。但看起来flask-restful默认情况下还不支持它。

于 2013-11-13T23:25:23.407 回答
3

要在您的 Web 服务 api 上允许远程 CORS 请求,您可以像这样简单地初始化您的烧瓶 restful API:

from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
from flask_cors import CORS

app = Flask(__name__)
cors = CORS(app, resources={r"*": {"origins": "*"}})
api = Api(app)

这会将 CORS 标头添加到您的 api 实例中,并允许对来自每个源的每个路径的 CORS 请求。

于 2018-09-13T09:42:40.980 回答
1

我喜欢用一个装饰来解决。

def cross_origin(origin="*"):
    def cross_origin(func):
        @functools.wraps(func)
        def _decoration(*args, **kwargs):
            ret = func(*args, **kwargs)
            _cross_origin_header = {"Access-Control-Allow-Origin": origin,
                                    "Access-Control-Allow-Headers":
                                        "Origin, X-Requested-With, Content-Type, Accept"}
            if isinstance(ret, tuple):
                if len(ret) == 2 and isinstance(ret[0], dict) and isinstance(ret[1], int):
                    # this is for handle response like: ```{'status': 1, "data":"ok"}, 200```
                    return ret[0], ret[1], _cross_origin_header
                elif isinstance(ret, basestring):
                    response = make_response(ret)
                    response.headers["Access-Control-Allow-Origin"] = origin
                    response.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
                    return response
                elif isinstance(ret, Response):
                    ret.headers["Access-Control-Allow-Origin"] = origin
                    ret.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
                    return ret
                else:
                    raise ValueError("Cannot handle cross origin, because the return value is not matched!")
            return ret

        return _decoration

    return cross_origin

然后,在您的宁静 api 中使用装饰。

class ExampleRestfulApi(Resource)
    @cross_origin()
    def get(self):
        # allow all cross domain access
        pass

    @cross_origin(origin="192.168.1.100")
    def post(self):
        # allow 192.168.1.100 access
        pass
于 2015-09-14T09:26:16.807 回答
0

在从角度连接到我的烧瓶休息 api 并尝试了几乎所有方法时,我遇到了多种类型的 CORS 问题。
如果您想不受任何限制地访问所有网站,您可以在app.py脚本中添加以下代码:

from flask_cors import CORS , cross_origin

cors = CORS(app, resources={r"/*": {"origins": "*"}})

这将起作用,但建议您具有一些安全性,您可以随时在原始编辑

于 2020-08-19T07:34:25.280 回答