【问题标题】:Flask RESTful cross-domain issue with Angular: PUT, OPTIONS methodsAngular 的 Flask RESTful 跨域问题:PUT、OPTIONS 方法
【发布时间】:2013-11-26 13:56:13
【问题描述】:

我使用 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 处理程序?

【问题讨论】:

    标签: python angularjs flask cors flask-restful


    【解决方案1】:

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

    【讨论】:

    • 谢谢!完美运行。
    • 这是部分答案,直到我添加了@app.after_request stackoverflow.com/questions/23741362/…
    • 上面的代码按原样工作。您提供的链接显示了同一问题的不同解决方案。
    【解决方案2】:

    你可以使用 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') 返回响应

    【讨论】:

    • 黄金答案。我知道 Flask-CORS 对某些人来说更简单,但在一个锁定的系统上,你必须填写文件才能更改目录,更不用说软件了,这 7 行代码可以挽救生命。
    【解决方案3】:

    我通过重写我的 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。

    【讨论】:

      【解决方案4】:

      这个解决方法怎么样:

      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 请求。

      【讨论】:

        【解决方案5】:

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

        使用: from flask_cors import CORS

        【讨论】:

          【解决方案6】:

          你是对的,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默认还不支持。

          【讨论】:

            【解决方案7】:

            要在您的 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 请求。

            【讨论】:

              【解决方案8】:

              我喜欢用装饰来解决。

              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
              

              然后,在你的 restful 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
              

              【讨论】:

                【解决方案9】:

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

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

                这会起作用,但建议您使用一些安全性,您可以随时在原始位置进行编辑

                【讨论】:

                  猜你喜欢
                  • 2017-04-29
                  • 2021-05-09
                  • 2014-05-29
                  • 1970-01-01
                  • 2014-06-07
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-06-05
                  • 1970-01-01
                  相关资源
                  最近更新 更多