Cách bật CORS trong bình


90

Tôi đang cố gắng thực hiện một yêu cầu gốc chéo bằng cách sử dụng jquery nhưng nó vẫn bị từ chối với thông báo

XMLHttpRequest không thể tải http: // ... Không có tiêu đề 'Access-Control-Allow-Origin' có trên tài nguyên được yêu cầu. Nguồn gốc ... do đó không được phép truy cập.

Tôi đang sử dụng flask, heroku và jquery

mã khách hàng trông như thế này:

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

về phía heroku tôi đang sử dụng bình và nó giống như thế này

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

Câu trả lời:


165

Đây là những gì đã làm việc cho tôi khi tôi triển khai Heroku.

http://flask-cors.readthedocs.org/en/latest/
Cài đặt flask-cors bằng cách chạy - 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!"

32
Thêm 1 cho hello cross origin world!
Simon Nicholls

đó là giải pháp duy nhất phù hợp với tôi. Cảm ơn!
psc37

1
Bạn là một vị cứu tinh! Làm việc như người ở.
Rohit Swami

Chào! Bạn có thể giúp tôi tìm ra những gì xảy ra trong trường hợp của tôi? Tôi đã viết một API đơn giản bằng Python / Flask, thậm chí không có chế độ xem cho nó. Tôi đã đạt được nó bằng curllệnh. Bây giờ tôi đã viết một trang html ngắn và cố gắng thực hiện một yêu cầu bằng phương thức JS fetch () tới API của tôi dựa trên Heroku và tôi gặp lỗi CORS. Sau khi tôi áp dụng mã của bạn, thiết bị đầu cuối của tôi bắt đầu phản hồi với tôi bằng mã HTML (HTTP / 1.1 503 Dịch vụ Không khả dụng) thay vì JSON. Điều gì có thể là một lỗi ở đây? Cảm ơn bạn!!
Nikita Basharkin

5
Trước khi bất kỳ ai sao chép mã này vào ứng dụng của họ, vui lòng kiểm tra tài liệu vì chỉ cần một số dòng này.
rovyko

45

OK, tôi không nghĩ rằng đoạn mã chính thức được đề cập bởi galuszkak nên được sử dụng ở mọi nơi, chúng tôi nên lo lắng trường hợp một số lỗi có thể được kích hoạt trong trình xử lý chẳng hạn như hello_worldhàm. Cho dù câu trả lời là chính xác hay không chính xác, Access-Control-Allow-Origintiêu đề là những gì chúng ta nên quan tâm. Vì vậy, mọi thứ rất đơn giản, giống như dưới đây:

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

Chỉ vậy thôi ~~


Điều này cũng đã giúp tôi cho một dự án nhỏ với các hoạt động CRUD cơ bản. Không cần bất cứ điều gì lạ mắt, chỉ cần bỏ qua các lỗi :)
Narshe

34

Tôi vừa phải đối mặt với vấn đề tương tự và tôi tin rằng các câu trả lời khác phức tạp hơn một chút so với mức cần thiết, vì vậy đây là cách tiếp cận của tôi dành cho những người không muốn dựa vào nhiều thư viện hoặc trình trang trí:

Một yêu cầu CORS thực sự bao gồm hai yêu cầu HTTP. Yêu cầu preflight và sau đó là một yêu cầu thực tế chỉ được thực hiện nếu preflight vượt qua thành công.

Yêu cầu preflight

Trước khi có POSTyêu cầu tên miền chéo thực sự , trình duyệt sẽ đưa ra một OPTIONSyêu cầu. Phản hồi này sẽ không trả về bất kỳ nội dung nào, mà chỉ có một số tiêu đề trấn an cho trình duyệt biết rằng việc thực hiện yêu cầu tên miền chéo này là ổn và nó không phải là một phần của một số cuộc tấn công tập lệnh trang web chéo.

Tôi đã viết một hàm Python để xây dựng phản hồi này bằng cách sử dụng make_responsehàm từ flaskmô-đun.

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

Phản hồi này là một ký tự đại diện hoạt động cho tất cả các yêu cầu. Nếu bạn muốn CORS tăng cường bảo mật, bạn phải cung cấp danh sách trắng về nguồn gốc, tiêu đề và phương thức.

Phản hồi này sẽ thuyết phục trình duyệt (Chrome) của bạn tiếp tục và thực hiện yêu cầu thực tế.

Yêu cầu thực tế

Khi phục vụ yêu cầu thực tế, bạn phải thêm một tiêu đề CORS - nếu không trình duyệt sẽ không trả lại phản hồi cho mã JavaScript đang gọi. Thay vào đó, yêu cầu sẽ không thành công ở phía máy khách. Ví dụ với jsonify

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

Tôi cũng đã viết một hàm cho điều đó.

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

cho phép bạn trả lại một lớp lót.

Mã cuối cùng

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("Weird - 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

Cảm ơn @Niels B. rất nhiều, bạn đã tiết kiệm thời gian của tôi. Tôi đã thêm cấu hình cors trước đây nhưng không thiết lập chính xác.
Günay Gültekin

1
Đây là câu trả lời tốt nhất cho vấn đề CORS này trên Flask. Làm việc như người ở! Cảm ơn @Niels
Chandra Kanth

Cảm ơn bạn đã giải thích rất chi tiết của bạn !! Điều này rất hữu ích!
jones-chris

Sử dụng nhiều giải pháp, bao gồm cả CORS và của bạn, nhưng tất cả chúng đều không hoạt động với aws (hãy làm theo ví dụ này - aws.amazon.com/getting-started/projects/… ), có ai biết chuyện gì đang xảy ra không?
StereoMatching

Giải pháp này thực sự đơn giản nhưng thanh lịch! Cảm ơn, bạn thực sự đã tiết kiệm thời gian của tôi.
Gerry

20

Nếu bạn muốn kích hoạt CORS cho tất cả các tuyến đường, sau đó chỉ cần cài đặt flask_cors mở rộng ( pip3 install -U flask_cors) và bọc appnhư thế này: CORS(app).

Điều đó là đủ để làm điều đó (Tôi đã thử nghiệm điều này với POSTyêu cầu tải lên một hình ảnh và nó đã hoạt động với tôi):

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

Lưu ý quan trọng: nếu có lỗi trong lộ trình của bạn, giả sử bạn cố gắng in một biến không tồn tại, bạn sẽ nhận được thông báo liên quan đến lỗi CORS, trên thực tế, không liên quan gì đến CORS.


1
Cảm ơn rất nhiều! Giải pháp đơn giản và chung này cho phép tôi gọi API của mình từ mã web React mà không cần khối CORS nữa.
Sebastian Diaz

1
Cảm ơn bạn ! Phần ghi chú quan trọng đã tiết kiệm cho tôi khá nhiều thời gian.
Gabriel

4

Hãy thử các cách trang trí sau:

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

Trình trang trí này sẽ được tạo như sau:

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

Bạn cũng có thể xem gói này Flask-CORS


vẫn không làm việc. Tôi đã thử điều đó và tôi cũng đã sử dụng gói Flask-CORS. Tôi nghĩ Flask-CORS được xây dựng trên đầu trang của rằng
Lopes

2

Giải pháp của tôi là một trình bao bọc xung quanh app.route:

def corsapp_route(path, origin=('127.0.0.1',), **options):
    """
    Flask app alias with cors
    :return:
    """

    def inner(func):
        def wrapper(*args, **kwargs):
            if request.method == 'OPTIONS':
                response = make_response()
                response.headers.add("Access-Control-Allow-Origin", ', '.join(origin))
                response.headers.add('Access-Control-Allow-Headers', ', '.join(origin))
                response.headers.add('Access-Control-Allow-Methods', ', '.join(origin))
                return response
            else:
                result = func(*args, **kwargs)
            if 'Access-Control-Allow-Origin' not in result.headers:
                result.headers.add("Access-Control-Allow-Origin", ', '.join(origin))
            return result

        wrapper.__name__ = func.__name__

        if 'methods' in options:
            if 'OPTIONS' in options['methods']:
                return app.route(path, **options)(wrapper)
            else:
                options['methods'].append('OPTIONS')
                return app.route(path, **options)(wrapper)

        return wrapper

    return inner

@corsapp_route('/', methods=['POST'], origin=['*'])
def hello_world():
    ...

2

Cải tiến giải pháp được mô tả tại đây: https://stackoverflow.com/a/52875875/10299604

Với việc này, after_requestchúng tôi có thể xử lý các tiêu đề phản hồi CORS tránh để thêm mã bổ sung vào các điểm cuối của chúng tôi:

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

1

Tất cả các phản hồi ở trên hoạt động ổn, nhưng bạn vẫn có thể gặp lỗi CORS, nếu ứng dụng gặp lỗi mà bạn không xử lý, chẳng hạn như lỗi khóa, nếu bạn không thực hiện xác thực đầu vào đúng cách chẳng hạn. Bạn có thể thêm trình xử lý lỗi để bắt tất cả các trường hợp ngoại lệ và thêm tiêu đề phản hồi CORS trong phản hồi của máy chủ

Vì vậy, hãy xác định một trình xử lý lỗi - error.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

sau đó sử dụng câu trả lời của Billal :

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 

1

Tôi đã giải quyết vấn đề tương tự này trong python bằng cách sử dụng bình và với thư viện này. flask_cors

Tham khảo: https://flask-cors.readthedocs.io/en/latest/


Mặc dù liên kết này có thể trả lời câu hỏi, nhưng tốt hơn hết bạn nên đưa các phần thiết yếu của câu trả lời vào đây và cung cấp liên kết để tham khảo. Các câu trả lời chỉ có liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
Jason Aller

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.