如何在Flask中启用CORS

236 投票
12 回答
377491 浏览
提问于 2025-04-19 02:37

我正在尝试使用jquery进行跨域请求,但总是被拒绝,错误信息是:

XMLHttpRequest无法加载http://... 请求的资源上没有'Access-Control-Allow-Origin'头信息。因此,来源...不被允许访问。

我使用的是flask、heroku和jquery。

客户端代码大概是这样的:

$(document).ready(function() {
    $('#submit_contact').click(function(e){
        e.preventDefault();
        $.ajax({
            type: 'POST',
            url: 'http://...',
            // data: [
            //      { name: "name", value: $('name').val()},
            //      { name: "email", value: $('email').val() },
            //      { name: "phone", value: $('phone').val()},
            //      { name: "description", value: $('desc').val()}
            //
            // ],
            data:"name=3&email=3&phone=3&description=3",
            crossDomain:true,
            success: function(msg) {
                alert(msg);
            }
        });
    }); 
});

在heroku这边,我使用flask,代码是这样的:

from flask import Flask,request
from flask.ext.mandrill import Mandrill
try:
    from flask.ext.cors import CORS  # The typical way to import flask-cors
except ImportError:
    # Path hack allows examples to be run without installation.
    import os
    parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    os.sys.path.insert(0, parentdir)

    from flask.ext.cors import CORS
app = Flask(__name__)

app.config['MANDRILL_API_KEY'] = '...'
app.config['MANDRILL_DEFAULT_FROM']= '...'
app.config['QOLD_SUPPORT_EMAIL']='...'
app.config['CORS_HEADERS'] = 'Content-Type'

mandrill = Mandrill(app)
cors = CORS(app)

@app.route('/email/',methods=['POST'])
def hello_world():
    name=request.form['name']
    email=request.form['email']
    phone=request.form['phone']
    description=request.form['description']

    mandrill.send_email(
        from_email=email,
        from_name=name,
        to=[{'email': app.config['QOLD_SUPPORT_EMAIL']}],
        text="Phone="+phone+"\n\n"+description
    )

    return '200 OK'

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

12 个回答

22

我在用Python和Flask解决这个问题的时候,使用了一个库,叫flask_cors

init.py文件里,你只需要这样写:

#pip install flask_cors

from flask_cors import CORS

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

就这样简单。

参考链接:https://flask-cors.readthedocs.io/en/latest/

53

如果你想让所有的路由都支持跨域请求(CORS),那么只需要安装一个叫做 flask_cors 的扩展(可以用命令 pip3 install -U flask_cors 来安装),然后像这样包裹你的 appCORS(app)

这样就可以了(我测试过用 POST 请求上传图片,这个方法对我有效):

from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # This will enable CORS for all routes

重要提示:如果你的路由里有错误,比如你试图打印一个不存在的变量,你会看到一个和 CORS 相关的错误信息,但其实这个错误和 CORS 没有关系。

69

好的,我觉得galuszkak提到的官方代码片段不应该随便用到任何地方。我们要考虑到在处理程序中,比如hello_world函数,可能会出现一些错误。无论响应是正确还是不正确,我们最关心的就是Access-Control-Allow-Origin这个头信息。所以,这个问题其实很简单,就像下面的代码片段:

# define your bluprint
from flask import Blueprint
blueprint = Blueprint('blueprint', __name__)

# put this sippet ahead of all your bluprints
# blueprint can also be app~~
@blueprint.after_request 
def after_request(response):
    header = response.headers
    header['Access-Control-Allow-Origin'] = '*'
    # Other headers can be added here if needed
    return response

# write your own blueprints with business logics
@blueprint.route('/test', methods=['GET'])
def test():
    return "test success"

就这些~~

101

我刚遇到同样的问题,觉得其他的回答有点复杂,所以我想分享一个简单的方法,适合那些不想依赖更多库或装饰器的人。

CORS请求其实包含两个HTTP请求。第一个是预检请求,只有当这个预检请求成功后,才会发出真正的请求。

预检请求

在实际的跨域POST请求之前,浏览器会先发出一个OPTIONS请求。这个请求的响应不应该返回任何内容,只需要一些让浏览器放心的头信息,告诉它可以进行这个跨域请求,并且这不是某种跨站脚本攻击。

我写了一个Python函数,利用flask模块中的make_response函数来构建这个响应。

def _build_cors_preflight_response():
    response = make_response()
    response.headers.add("Access-Control-Allow-Origin", "*")
    response.headers.add("Access-Control-Allow-Headers", "*")
    response.headers.add("Access-Control-Allow-Methods", "*")
    return response

这个响应是一个通配符响应,适用于所有请求。如果你想要CORS带来的额外安全性,就需要提供一个允许的来源、头信息和方法的白名单。

这个响应会让你的(Chrome)浏览器继续进行实际的请求。

实际请求

在处理实际请求时,你需要添加一个CORS头信息,否则浏览器不会把响应返回给调用的JavaScript代码。这样请求就会在客户端失败。下面是一个使用jsonify的例子。

response = jsonify({"order_id": 123, "status": "shipped"})
response.headers.add("Access-Control-Allow-Origin", "*")
return response

我也为这个写了一个函数。

def _corsify_actual_response(response):
    response.headers.add("Access-Control-Allow-Origin", "*")
    return response

这样你就可以返回一行代码。

最终代码

from flask import Flask, request, jsonify, make_response
from models import OrderModel

flask_app = Flask(__name__)

@flask_app.route("/api/orders", methods=["POST", "OPTIONS"])
def api_create_order():
    if request.method == "OPTIONS": # CORS preflight
        return _build_cors_preflight_response()
    elif request.method == "POST": # The actual request following the preflight
        order = OrderModel.create(...) # Whatever.
        return _corsify_actual_response(jsonify(order.to_dict()))
    else:
        raise RuntimeError("Weird - don't know how to handle method {}".format(request.method))

def _build_cors_preflight_response():
    response = make_response()
    response.headers.add("Access-Control-Allow-Origin", "*")
    response.headers.add('Access-Control-Allow-Headers', "*")
    response.headers.add('Access-Control-Allow-Methods', "*")
    return response

def _corsify_actual_response(response):
    response.headers.add("Access-Control-Allow-Origin", "*")
    return response
396

这是我在把项目部署到Heroku时有效的方法。

你可以查看这个链接了解更多信息:http://flask-cors.readthedocs.org/en/latest/

要安装flask-cors这个库,你可以在命令行中运行以下命令:

pip install -U flask-cors

这条命令会帮你安装或更新flask-cors。

from flask import Flask
from flask_cors import CORS, cross_origin
app = Flask(__name__)
cors = CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'

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

撰写回答