使用Angular:PUT,OPTIONS方法的Flask RESTful跨域问题

时间:2013-11-13 19:31:04

标签: python angularjs flask cors flask-restful

我开发了一个带有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?我之前使用了带有(非宁静的)Flask实例的cross-domaion装饰器,但是我是否需要在我的API中编写OPTIONS处理程序?

9 个答案:

答案 0 :(得分:45)

使用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": "*"}})

答案 1 :(得分:19)

您可以使用after_request钩子:

@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

查看本教程以获取更多详细信息 - http://tutsbucket.com/tutorials/building-a-blog-using-flask-and-angularjs-part-1/

答案 2 :(得分:18)

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

PUT方法的返回如下所示:

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

My 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标题,浏览器似乎对此感到满意,并使用PUT跟进了OPTIONS。

答案 3 :(得分:4)

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

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

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

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

答案 4 :(得分:3)

只是对此评论的更新。 Flask CORS是可行的方法,但不推荐使用flask.ext.cors。

使用: from flask_cors import CORS

答案 5 :(得分:2)

这个解决方法怎么样:

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

我是从this教程中学到的。效果很好。实际上,我认为这是迄今为止我见过的最佳方法。

在每个端点上返回{'Access-Control-Allow-Origin': '*'}似乎没有效率,因为您必须在每个端点上添加它。有点恼人......至少对我而言。

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

答案 6 :(得分:0)

我喜欢用装饰来解决。

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

答案 7 :(得分:0)

要在您的Web服务api上允许远程CORS请求,您可以像这样简单地初始化flask 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请求。

答案 8 :(得分:0)

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

from flask_cors import CORS , cross_origin

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

这可以工作,但是建议您具有一定的安全性,您可以随时在原始位置进行编辑