Python 用 Flask 解决跨域资源共享

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26980713/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 01:15:06  来源:igfitidea点击:

Solve Cross Origin Resource Sharing with Flask

javascriptpythonajaxflaskcors

提问by Matteo

For the following ajaxpost request for Flask(how can I use data posted from ajax in flask?):

对于以下ajax发布请求Flask如何使用从 ajax 在 Flask 中发布的数据?):

$.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 );
    }   
});

I get a Cross Origin Resource Sharing (CORS)error:

我收到一个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.

I tried solving it in the two following ways, but none seems to work.

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

  1. Using Flask-CORS
  1. 使用 Flask-CORS

This is a Flaskextension for handling CORSthat should make cross-origin AJAX possible.

这是一个Flask处理扩展CORS,应该使跨域 AJAX 成为可能。

My pythonServer.pyusing this solution:

我的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. Using specific Flask Decorator
  1. 使用特定的 Flask 装饰器

This is an officialFlask code snippet defining a decorator that should allow CORSon the functions it decorates.

这是一个官方的Flask 代码片段,定义了一个装饰器,它应该允许CORS它装饰的函数。

My pythonServer.pyusing this solution:

我的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()

Can you please give some some indication of why that is?

你能给出一些说明为什么会这样吗?

采纳答案by Satish

It worked like a champ, after bit modification to your code

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

# 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()

I replaced * by localhost. Since as I read in many blogs and posts, you should allow access for specific domain

我用 localhost 替换了 *。正如我在许多博客和帖子中所读到的那样,您应该允许访问特定域

回答by Per Kristian

I struggled a lot with something similar. Try the following:

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

  1. Use some sort of browser plugin which can display the HTML headers.
  2. Enter the URL to your service, and view the returned header values.
  3. Make sure Access-Control-Allow-Origin is set to one and only one domain, which should be the request origin. Do not set Access-Control-Allow-Origin to *.
  1. 使用某种可以显示 HTML 标题的浏览器插件。
  2. 输入您的服务的 URL,并查看返回的标头值。
  3. 确保 Access-Control-Allow-Origin 设置为一个且只有一个域,该域应该是请求源。不要将 Access-Control-Allow-Origin 设置为 *。

If this doesn't help, take a look at this article. It's on PHP, but it describes exactly which headers must be set to which values for CORS to work.

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

CORS That Works In IE, Firefox, Chrome And Safari

适用于 IE、Firefox、Chrome 和 Safari 的 CORS

回答by Jaza

Note that setting the Access-Control-Allow-Originheader in the Flask response object is fine in many cases (such as this one), but it has no effect when serving static assets (in a production setup, at least). That's because static assets are served directly by the front-facing web server (usually Nginx or Apache). So, in that case, you have to set the response header at the web server level, not in Flask.

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

For more details, see this article that I wrote a while back, explaining how to set the headers(in my case, I was trying to do cross-domain serving of Font Awesome assets).

有关更多详细信息,请参阅我不久前写的这篇文章,其中解释了如何设置标题(在我的例子中,我试图对 Font Awesome 资产进行跨域服务)。

Also, as @Satu said, you may need to allow access only for a specific domain, in the case of JS AJAX requests. For requesting static assets (like font files), I think the rules are less strict, and allowing access for any domain is more accepted.

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

回答by Salvador Dali

You can get the results with a simple:

您可以通过简单的方式获得结果:

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

回答by Juha Untinen

Might as well make this an answer. I had the same issue today and it was more of a non-issue than expected. After adding the CORS functionality, you mustrestart your Flask server (ctrl + c-> python manage.py runserver, or whichever method you use)) in order for the change to take effect, even if the code is correct. Otherwise the CORS will not work in the active instance.

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

Here's how it looks like for me and it works (Python 3.6.1, Flask 0.12):

这是我的样子和它的工作原理(Python 3.6.1,Flask 0.12):

factory.py:

工厂.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:

视图.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"
        })

In my React app console.log:

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

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

回答by Nagashayan

Well, I faced the same issue. For new users who may land at this page. Just follow their official documentation.

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

Install flask-cors

安装 Flask-cors

pip install -U flask-cors

then after app initialization, initialize flask-corswith default arguments:

然后在应用程序初始化后,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!"

回答by D.Waasala

I used decorator given by Armin Ronacherwith little modifications (due to different headers that are requested by the client).And that worked for me. (where I use angular as the requester requesting application/json type).

我使用了 Armin Ronacher提供的装饰器,稍作修改(由于客户端请求的标头不同)。这对我有用。(我使用 angular 作为请求应用程序/json 类型的请求者)。

The code is slightly modified at below places,

代码在以下地方略有修改,

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 will send a application/json type, else it will be text/html. headers are added as the client in my case request for those headers

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)

回答by Dila Gurung

Note: The placement of cross_origin should be right and dependencies are installed. On the client side, ensure to specify kind of data server is consuming. For example application/json or text/html

注意:cross_origin 的位置应该是对的,并且已经安装了依赖。在客户端,确保指定服务器正在消耗的数据类型。例如 application/json 或 text/html

For me the code written below did magic

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

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)