【问题标题】:Solve Cross Origin Resource Sharing with Flask使用 Flask 解决跨域资源共享
【发布时间】:2015-01-14 20:07:24
【问题描述】:

对于Flask (how can I use data posted from ajax in flask?) 的以下ajax 发布请求:

$.ajax({
    url: "http://127.0.0.1:5000/foo", 
    type: "POST",
    contentType: "application/json",
    data: JSON.stringify({'inputVar': 1}),
    success: function( data ) { 
        alert( "success" + data );
    }   
});

我收到 Cross Origin Resource Sharing (CORS) 错误:

No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'null' is therefore not allowed access. 
The response had HTTP status code 500.

我尝试通过以下两种方式解决它,但似乎都不起作用。

  1. 使用 Flask-CORS

这是一个用于处理 CORSFlask 扩展,应该可以实现跨域 AJAX。

我的 pythonServer.py 使用这个解决方案:

from flask import Flask
from flask.ext.cors import CORS, cross_origin

app = Flask(__name__)
cors = CORS(app, resources={r"/foo": {"origins": "*"}})
app.config['CORS_HEADERS'] = 'Content-Type'

@app.route('/foo', methods=['POST','OPTIONS'])
@cross_origin(origin='*',headers=['Content-Type','Authorization'])
def foo():
    return request.json['inputVar']

if __name__ == '__main__':
    app.run()
  1. 使用特定的 Flask Decorator

这是一个官方 Flask 代码 sn-p 定义了一个装饰器,它应该允许 CORS 在它装饰的函数上。

我的 pythonServer.py 使用这个解决方案:

from flask import Flask, make_response, request, current_app
from datetime import timedelta
from functools import update_wrapper

app = Flask(__name__)

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

@app.route('/foo', methods=['GET','POST','OPTIONS'])
@crossdomain(origin="*")
def foo():
    return request.json['inputVar']

if __name__ == '__main__':
    app.run()

您能否说明原因?

【问题讨论】:

  • 你发现了吗?我遇到了完全相同的问题:(
  • 这是一个老问题,但为了确定:您是否重新启动了 Flask 服务器?我也想知道为什么我得到了同样的错误,即使我认为一切都和他们应该的完全一样。事实证明,您必须重新启动服务器才能真正生效

标签: javascript python ajax flask cors


【解决方案1】:

你可以通过一个简单的方法得到结果:

@app.route('your route', methods=['GET'])
def yourMethod(params):
    response = flask.jsonify({'some': 'data'})
    response.headers.add('Access-Control-Allow-Origin', '*')
    return response

【讨论】:

  • 添加跨域实现更好!
  • 简单有效
  • 太棒了!我同意,简单有效。 IMO 应该被接受的答案
  • @Salvador Dali - 如果我渲染模板而不仅仅是 json 对象,你知道什么是允许跨源的正确方法吗?即yourMethod 中的最后一行代码是:return render_template('template.html',some_var = response)
  • 这可以用在 post 方法中吗?我尝试了一种文件上传方法,但失败了。
【解决方案2】:

好吧,我遇到了同样的问题。对于可能登陆此页面的新用户。 只需遵循他们的官方文档即可。

安装烧瓶-cors

pip install -U flask-cors

然后在应用初始化之后,使用默认参数初始化flask-cors

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
   return "Hello, cross-origin-world!"

【讨论】:

  • 这给了我以下错误访问来自原点“127.0.0.1:5000”的“my_domain”处的 XMLHttpRequest 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:“ Access-Control-Allow-Origin' 标头包含多个值 '127.0.0.1:5000, *',但只允许一个。
  • 对我不起作用。 *.com/questions/59652099/…
  • 对我也有用 Tks!
  • 如何为flask_cors设置Access-Control-Max-Age
  • 为我工作!!谢谢你。这应该是公认的答案!
【解决方案3】:

在对您的代码进行一些修改后,它就像一个冠军一样工作

# initialization
app = Flask(__name__)
app.config['SECRET_KEY'] = 'the quick brown fox jumps over the lazy   dog'
app.config['CORS_HEADERS'] = 'Content-Type'

cors = CORS(app, resources={r"/foo": {"origins": "http://localhost:port"}})

@app.route('/foo', methods=['POST'])
@cross_origin(origin='localhost',headers=['Content- Type','Authorization'])
def foo():
    return request.json['inputVar']

if __name__ == '__main__':
   app.run()

我将 * 替换为 localhost。因为正如我在许多博客和帖子中看到的那样,您应该允许特定域的访问

【讨论】:

  • 如果有人在使用蓝图,则需要将 CORS() 添加到每个蓝图中,例如:my_blueprint = Blueprint('my_bp_name', name, url_prefix=" /my-prefix") CORS(my_blueprint)
  • 也请参见下面的单行:*.com/a/46637194/3559330
【解决方案4】:

不妨将此作为答案。我今天遇到了同样的问题,这比预期的更不是问题。添加 CORS 功能后,您必须重新启动 Flask 服务器(ctrl + c -> python manage.py runserver,或您使用的任何方法)以使更改生效,即使代码是正确的。否则 CORS 将无法在活动实例中工作。

这对我来说是这样的,它的工作原理是这样的(Python 3.6.1,Flask 0.12):

factory.py

from flask import Flask
from flask_cors import CORS  # This is the magic


def create_app(register_stuffs=True):
    """Configure the app and views"""
    app = Flask(__name__)
    CORS(app)  # This makes the CORS feature cover all routes in the app

    if register_stuffs:
        register_views(app)
    return app


def register_views(app):
    """Setup the base routes for various features."""
    from backend.apps.api.views import ApiView
    ApiView.register(app, route_base="/api/v1.0/")

views.py

from flask import jsonify
from flask_classy import FlaskView, route


class ApiView(FlaskView):
    @route("/", methods=["GET"])
    def index(self):
        return "API v1.0"

    @route("/stuff", methods=["GET", "POST"])
    def news(self):
        return jsonify({
            "stuff": "Here be stuff"
        })

在我的 React 应用程序 console.log 中:

Sending request:
GET /stuff
With parameters:
null
bundle.js:17316 Received data from Api:
{"stuff": "Here be stuff"}

【讨论】:

    【解决方案5】:

    请注意,在许多情况下(例如这种情况),在 Flask 响应对象中设置 Access-Control-Allow-Origin 标头是可以的,但在提供静态资产时(至少在生产设置中)没有效果。这是因为静态资产直接由前端 Web 服务器(通常是 Nginx 或 Apache)提供服务。因此,在这种情况下,您必须在 Web 服务器级别设置响应标头,而不是在 Flask 中。

    有关更多详细信息,请参阅我不久前写的这篇文章,explaining how to set the headers(在我的例子中,我试图对 Font Awesome 资产进行跨域服务)。

    另外,正如@Satu 所说,在 JS AJAX 请求的情况下,您可能只需要允许特定域的访问。对于请求静态资产(如字体文件),我认为规则不那么严格,允许访问任何域更容易接受。

    【讨论】:

      【解决方案6】:

      注意:cross_origin 的位置要正确并安装依赖。 在客户端,确保指定服务器正在使用的数据类型。例如 application/json 或 text/html

      对我来说,下面写的代码很神奇

      from flask import Flask,request,jsonify
      from flask_cors import CORS,cross_origin
      app=Flask(__name__)
      CORS(app, support_credentials=True)
      @app.route('/api/test', methods=['POST', 'GET','OPTIONS'])
      @cross_origin(supports_credentials=True)
      def index():
          if(request.method=='POST'):
           some_json=request.get_json()
           return jsonify({"key":some_json})
          else:
              return jsonify({"GET":"GET"})
      
      
      if __name__=="__main__":
          app.run(host='0.0.0.0', port=5000)
      

      【讨论】:

      • 你为什么在cross_origin做同样的事情(support_credentials=True)?
      【解决方案7】:

      我可能在这个问题上迟到了,但下面的步骤解决了这个问题

      from flask import Flask
      from flask_cors import CORS
      
      app = Flask(__name__)
      CORS(app)
      

      【讨论】:

        【解决方案8】:

        我使用了decorator given by Armin Ronacher 并进行了少量修改(由于客户端请求的标头不同)。这对我有用。 (我使用 angular 作为请求应用程序/json 类型的请求者)。

        代码在以下地方稍作修改,

        from flask import jsonify
        
        @app.route('/my_service', methods=['POST', 'GET','OPTIONS'])
        @crossdomain(origin='*',headers=['access-control-allow-origin','Content-Type'])
        def my_service():
            return jsonify(foo='cross domain ftw')
        

        jsonify 将发送一个 application/json 类型,否则它将是 text/html。 在我对这些标头的请求中,标头被添加为客户端

         const httpOptions = {
              headers: new HttpHeaders({
                'Content-Type': 'application/json',
                'Access-Control-Allow-Origin':'*'
              })
            };
            return this.http.post<any>(url, item,httpOptions)
        

        【讨论】:

        • 装饰器链接失效
        【解决方案9】:

        这已经是一个相当古老且覆盖面广的问题了,但我想我会贡献我认为最简单的解决方案:

        @app.after_request
        def after_request(response: Response) -> Response:
            response.access_control_allow_origin = "*"
            return response
        

        【讨论】:

          【解决方案10】:

          我在类似的事情上挣扎了很多。请尝试以下操作:

          1. 使用某种可以显示 HTML 标头的浏览器插件。
          2. 输入服务的 URL,并查看返回的标头值。
          3. 确保将 Access-Control-Allow-Origin 设置为一个且只有一个域,该域应该是请求源。不要将 Access-Control-Allow-Origin 设置为 *。

          如果这没有帮助,请查看这篇文章。它在 PHP 上,但它准确描述了必须将哪些标头设置为哪些值才能使 CORS 工作。

          CORS That Works In IE, Firefox, Chrome And Safari

          【讨论】:

          • 1) 标头来自 HTTP 连接,而不是 HTML 文档 2) 您可以在任何现代浏览器上打开您的 devtools 以在“网络”选项卡下显示连接的标头,而无需安装任何扩展 3 ) 如果您不想为每个请求设置自定义标头并且您希望例如创建公共 API,则可能需要在 Access-Control-Allow-Origin 中使用 *