如何在flask和heroku中启用CORS

Lop*_*pes 38 python jquery heroku cors flask

我正在尝试使用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);
            }
        });
    }); 
});
Run Code Online (Sandbox Code Playgroud)

在heroku方面,我正在使用烧瓶,就像这样

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()
Run Code Online (Sandbox Code Playgroud)

Dan*_*son 81

当我部署到Heroku时,这对我有用.

http://flask-cors.readthedocs.org/en/latest/

$ pip install -U 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!"
Run Code Online (Sandbox Code Playgroud)

  • 在任何人将此代码复制到他们的应用程序中之前,请[查看文档](https://flask-cors.readthedocs.io/en/3.0.7/),因为只需要这些行中的**一些**。 (10认同)
  • 是的,与 @rovyko 相呼应,此代码片段中使用了几个重叠的功能,因此请检查文档。对我来说,“from Flask_cors import CORS”后跟“CORS(app)”就足够了 (8认同)
  • 你好,跨世界起源加1! (2认同)
  • 你是一个生命的救星!工作起来就像一个魅力。 (2认同)

zha*_*gqy 26

好吧,我不认为galuszkak提到的官方片段应该在任何地方使用,我们应该关注在处理程序如hello_world函数期间可能触发某些错误的情况.无论响应是正确还是不正确,Access-Control-Allow-Origin标题都是我们应该关注的.所以,事情很简单,就像吼叫:

@blueprint.after_request # blueprint can also be app~~
def after_request(response):
    header = response.headers
    header['Access-Control-Allow-Origin'] = '*'
    return response
Run Code Online (Sandbox Code Playgroud)

这都是~~

  • 这种方法不需要废话。 (2认同)

S. *_*iss 10

您首先需要安装flask-cors. 您可以按如下方式执行此操作:

pip install flask-cors
Run Code Online (Sandbox Code Playgroud)

安装后,您可以在 Flask 应用程序中使用它,如下所示:

  1. 如果需要为所有路由启用CORS:
from flask_cors import CORS

app = Flask(__name__)
CORS(app)
Run Code Online (Sandbox Code Playgroud)
  1. 如果您只想启用CORS特定路由,可以将 resources 参数传递给该CORS函数。例如,
CORS(app, resources={r"/api/*": {"origins": "*"}})
Run Code Online (Sandbox Code Playgroud)

在此示例中,此代码将CORS仅启用以 开头的路由/api/,并允许来自任何来源的请求。您可以自定义资源参数以满足您的需求。

欲了解更多信息,请阅读文档


Ped*_*zco 7

我使用flask和这个库在python中解决了同样的问题。 文件init .py 中的flask_cors

#pip install flask_cors

from flask_cors import CORS

app = Flask(__name__)
CORS(app)
cors = CORS(app, resource={
    r"/*":{
        "origins":"*"
    }
})
Run Code Online (Sandbox Code Playgroud)

和它的全部。

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


Fra*_*bar 6

改进此处描述的解决方案:https : //stackoverflow.com/a/52875875/10299604

随着after_request我们可以处理CORS响应头避免额外的代码添加到我们的端点:

    ### CORS section
    @app.after_request
    def after_request_func(response):
        origin = request.headers.get('Origin')
        if request.method == 'OPTIONS':
            response = make_response()
            response.headers.add('Access-Control-Allow-Credentials', 'true')
            response.headers.add('Access-Control-Allow-Headers', 'Content-Type')
            response.headers.add('Access-Control-Allow-Headers', 'x-csrf-token')
            response.headers.add('Access-Control-Allow-Methods',
                                'GET, POST, OPTIONS, PUT, PATCH, DELETE')
            if origin:
                response.headers.add('Access-Control-Allow-Origin', origin)
        else:
            response.headers.add('Access-Control-Allow-Credentials', 'true')
            if origin:
                response.headers.add('Access-Control-Allow-Origin', origin)

        return response
    ### end CORS section
Run Code Online (Sandbox Code Playgroud)


Nie*_* B. 5

我刚刚遇到了同样的问题,我开始相信其他答案比他们需要的要复杂一些,因此对于那些不想依赖更多库或装饰器的人来说,这是我的方法:

一个CORS请求实际上包含两个HTTP请求。预检请求,然后只有在预检成功通过后才发出的实际请求。

飞行前要求

在实际的跨域POST请求之前,浏览器将发出一个OPTIONS请求。此响应不应返回任何正文,而应仅返回一些使人放心的标头,告诉浏览器可以执行此跨域请求,并且不属于某些跨站点脚本攻击的一部分。

我编写了一个Python函数来使用模块中的make_response函数构建此响应flask

def _build_cors_prelight_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
Run Code Online (Sandbox Code Playgroud)

此响应是通配符,适用于所有请求。如果您希望CORS获得额外的安全性,则必须提供源,标头和方法的白名单。

该响应将说服您的(Chrome)浏览器继续进行实际的请求。

实际要求

在处理实际请求时,您必须添加一个CORS标头-否则浏览器不会将响应返回到调用JavaScript代码。相反,请求将在客户端失败。jsonify示例

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

我也为此编写了一个函数。

def _corsify_actual_response(response):
    response.headers.add("Access-Control-Allow-Origin", "*")
    return response
Run Code Online (Sandbox Code Playgroud)

让您退货。

最终代码

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_prelight_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("Wierd - don't know how to handle method {}".format(request.method))

def _build_cors_prelight_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
Run Code Online (Sandbox Code Playgroud)

  • 这是迄今为止关于 Flask 上这个 CORS 问题的最佳答案。像魅力一样工作!谢谢@Niels (2认同)

Bil*_*adj 5

如果您想为所有路由启用CORS,则只需安装flask_cors扩展名(pip3 install -U flask_cors)并app像这样包装即可 :CORS(app)

做到这一点就足够了(我POST通过上传图片的请求对它进行了测试,并且对我有用):

from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # This will enable CORS for all routes
Run Code Online (Sandbox Code Playgroud)

重要说明:如果您的路线中有错误,可以说您尝试打印不存在的变量,则会收到与CORS错误相关的消息,而实际上该消息与CORS无关。

  • 谢谢 !重要的注释部分节省了我很多时间。 (4认同)
  • 正是这个。我仍然遇到 CORS 错误,但是当我运行 `heroku logs --tail` 时,我看到了 **模块导入错误**。然后我将“Flask-Cors==3.0.10”添加到“requirements.txt”文件中,并且它起作用了。我不必重新启动测功机。顺便说一句,您可以运行“pip freeze>requirements.txt”来自动获取所有模块需求。 (4认同)
  • 多谢!这个简单而通用的解决方案允许我从 React Web 代码中调用 API,而无需再使用 CORS 块。 (2认同)
  • 谢谢你!你的笔记是金子。 (2认同)

Edr*_*ich 5

上面的所有响应都可以正常工作,但是如果应用程序抛出一个您未处理的错误(例如按键错误),例如,如果您没有正确执行输入验证,您仍然可能会收到 CORS 错误。您可以添加错误处理程序来捕获所有异常实例,并在服务器响应中添加 CORS 响应标头

因此定义一个错误处理程序-errors.py:

from flask import json, make_response, jsonify
from werkzeug.exceptions import HTTPException

# define an error handling function
def init_handler(app):

    # catch every type of exception
    @app.errorhandler(Exception)
    def handle_exception(e):

        #loggit()!          

        # return json response of error
        if isinstance(e, HTTPException):
            response = e.get_response()
            # replace the body with JSON
            response.data = json.dumps({
                "code": e.code,
                "name": e.name,
                "description": e.description,
            })
        else:
            # build response
            response = make_response(jsonify({"message": 'Something went wrong'}), 500)

        # add the CORS header
        response.headers['Access-Control-Allow-Origin'] = '*'
        response.content_type = "application/json"
        return response
Run Code Online (Sandbox Code Playgroud)

然后使用比拉尔的答案:

from flask import Flask
from flask_cors import CORS

# import error handling file from where you have defined it
from . import errors

app = Flask(__name__)
CORS(app) # This will enable CORS for all routes
errors.init_handler(app) # initialise error handling 
Run Code Online (Sandbox Code Playgroud)


New*_*wtt 4

尝试以下装饰器:

@app.route('/email/',methods=['POST', 'OPTIONS']) #Added 'Options'
@crossdomain(origin='*')                          #Added
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()
Run Code Online (Sandbox Code Playgroud)

该装饰器将按如下方式创建:

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


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
Run Code Online (Sandbox Code Playgroud)

您还可以查看这个包Flask-CORS