Giải quyết việc chia sẻ tài nguyên nguồn gốc chéo với Flask


82

Đối với ajaxyêu cầu bài đăng sau cho Flask( làm cách nào tôi có thể sử dụng dữ liệu được đăng từ ajax trong 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 );
    }   
});

Tôi gặp Cross Origin Resource Sharing (CORS)lỗi:

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.

Tôi đã thử giải quyết nó theo hai cách sau đây, nhưng dường như không có cách nào hiệu quả.

  1. Sử dụng Flask-CORS

Đây là một Flasktiện ích mở rộng để xử lý CORSgiúp AJAX có nhiều nguồn gốc trở nên khả thi.

PythonServer.py của tôi bằng cách sử dụng giải pháp này:

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. Sử dụng Trình trang trí bình cụ thể

Đây là đoạn mã Flask chính thức xác định một trình trang trí sẽ cho phép CORScác chức năng mà nó trang trí.

PythonServer.py của tôi bằng cách sử dụng giải pháp này:

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

Bạn có thể vui lòng cho một số chỉ dẫn về lý do tại sao lại như vậy không?


bạn đã tìm ra? Tôi gặp phải cùng một vấn đề :(
shao

Đây là một câu hỏi cũ, nhưng chỉ để chắc chắn: Bạn đã khởi động lại máy chủ Flask của mình chưa? Tôi cũng tự hỏi tại sao tôi lại mắc phải lỗi tương tự thậm chí nghĩ rằng mọi thứ đều chính xác như họ nên làm. Hóa ra, bạn phải khởi động lại máy chủ để nó thực sự có hiệu lực
Juha Untinen

Câu trả lời:


50

Nó hoạt động như một nhà vô địch, sau khi sửa đổi một chút đối với mã của bạn

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

Tôi đã thay thế * bằng localhost. Vì khi tôi đọc trong nhiều blog và bài đăng, bạn nên cho phép truy cập vào miền cụ thể


2
Trong trường hợp có ai đang sử dụng bản thiết kế, bạn cần thêm CORS () vào mỗi bản thiết kế, ví dụ: my_blueprint = Blueprint ('my_bp_name', name , url_prefix = "/ my-prefix") CORS (my_blueprint)
BLang

88

Bạn có thể nhận được kết quả với một cách đơn giản:

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

1
Tốt hơn là thêm triển khai tên miền chéo!
Florescu Cătălin

Đơn giản và hiệu quả
Anthony

4
Xuất sắc! Tôi đồng ý, đơn giản và hiệu quả. IMO nên được chấp nhận câu trả lời
PALEN

3
@Salvador Dali - Bạn có biết cách thích hợp để cho phép nguồn gốc chéo là gì nếu tôi đang hiển thị một mẫu thay vì chỉ một đối tượng json không? tức là dòng mã cuối cùng trong yourMethodlà:return render_template('template.html',some_var = response)
Matteo,

3
Điều này có thể được sử dụng trong một phương pháp đăng bài? Tôi đã thử phương pháp tải tệp lên và không thành công.
W.Leto

61

Tôi cũng phải đối mặt với vấn đề tương tự. Đối với những người dùng mới có thể truy cập trang này. Chỉ cần làm theo tài liệu chính thức của họ.

Cài đặt cors bình

pip install -U flask-cors

thì sau khi khởi tạo ứng dụng, hãy khởi tạo flask-corsvới các đối số mặc định:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

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

Điều này gây ra lỗi sau cho tôi Quyền truy cập vào XMLHttpRequest tại 'my_domain' từ origin ' 127.0.0.1:5000 ' đã bị chặn bởi chính sách CORS: Phản hồi cho yêu cầu preflight không vượt qua kiểm tra kiểm soát truy cập: 'Access-Control-Allow- Tiêu đề Origin 'chứa nhiều giá trị' 127.0.0.1:5000 , * ', nhưng chỉ một giá trị được phép.
khiêm tốnPilgrim 19/07/19

Không hiệu quả với tôi. stackoverflow.com/questions/59652099/…
WP McNeill

Có tác dụng với tôi quá Tks!
Jose

Đã làm cho tôi! Cảm ơn rất nhiều :)
XpressGeek

làm thế nào để thiết lập Access-Control-Max-Agecho flask_cors?
DragonKnight

5

Cũng có thể làm cho điều này trở thành một câu trả lời. Tôi đã gặp vấn đề tương tự ngày hôm nay và nó không phải là vấn đề hơn mong đợi. Sau khi thêm chức năng CORS, bạn phải khởi động lại máy chủ Flask của mình ( ctrl + c-> python manage.py runserverhoặc bất kỳ phương pháp nào bạn sử dụng)) để thay đổi có hiệu lực, ngay cả khi mã chính xác. Nếu không, CORS sẽ không hoạt động trong trường hợp đang hoạt động.

Đây là cách nó trông như thế nào đối với tôi và nó hoạt động (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"
        })

Trong ứng dụng React console.log của tôi:

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

4

Lưu ý rằng việc đặt Access-Control-Allow-Origintiêu đề trong đối tượng phản hồi Flask là tốt trong nhiều trường hợp (chẳng hạn như trường hợp này), nhưng nó không có tác dụng khi cung cấp nội dung tĩnh (ít nhất là trong thiết lập sản xuất). Đó là bởi vì nội dung tĩnh được phân phát trực tiếp bởi máy chủ web phía trước (thường là Nginx hoặc Apache). Vì vậy, trong trường hợp đó, bạn phải đặt tiêu đề phản hồi ở cấp máy chủ web, không phải trong Flask.

Để biết thêm chi tiết, hãy xem bài viết mà tôi đã viết trước đây, giải thích cách đặt tiêu đề (trong trường hợp của tôi, tôi đang cố gắng thực hiện phân phối nội dung Font Awesome trên nhiều miền).

Ngoài ra, như @Satu đã nói, bạn có thể chỉ cần cho phép truy cập cho một miền cụ thể, trong trường hợp yêu cầu JS AJAX. Đối với việc yêu cầu nội dung tĩnh (như tệp phông chữ), tôi nghĩ các quy tắc ít nghiêm ngặt hơn và việc cho phép truy cập cho bất kỳ miền nào được chấp nhận nhiều hơn.


3

Tôi đã sử dụng trình trang trí do Armin Ronacher cung cấp với một số sửa đổi nhỏ (do khách hàng yêu cầu các tiêu đề khác nhau). Và điều đó phù hợp với tôi. (trong đó tôi sử dụng angle làm người yêu cầu ứng dụng / loại json).

Mã được sửa đổi một chút ở những vị trí bên dưới,

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 sẽ gửi một loại ứng dụng / json, nếu không nó sẽ là văn bản / html. các tiêu đề được thêm vào dưới dạng khách hàng trong trường hợp của tôi yêu cầu các tiêu đề đó

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

2
Liên kết đến trình trang trí đã chết
José Tomás Tocino

2

Lưu ý: Vị trí của cross_origin phải đúng và các phần phụ thuộc được cài đặt. Về phía máy khách, hãy đảm bảo chỉ định loại máy chủ dữ liệu đang sử dụng. Ví dụ: application / json hoặc text / html

Đối với tôi đoạn mã được viết dưới đây đã làm nên điều kỳ diệu

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)

tại sao bạn làm điều tương tự (support_credentials = True) trong cross_origin?
Eziz Durdyyev

0

Tôi đã đấu tranh rất nhiều với một cái gì đó tương tự. Hãy thử những cách sau:

  1. Sử dụng một số loại plugin trình duyệt có thể hiển thị các tiêu đề HTML.
  2. Nhập URL cho dịch vụ của bạn và xem các giá trị tiêu đề được trả về.
  3. Đảm bảo Access-Control-Allow-Origin được đặt thành một và chỉ một miền, miền này phải là nguồn gốc yêu cầu. Không đặt Access-Control-Allow-Origin thành *.

Nếu điều này không hữu ích, hãy xem bài viết này. Nó trên PHP, nhưng nó mô tả chính xác tiêu đề nào phải được đặt thành giá trị nào để CORS hoạt động.

CORS hoạt động trên IE, Firefox, Chrome và Safari


0

Tôi có thể đến muộn với câu hỏi này nhưng các bước dưới đây đã khắc phục sự cố

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)
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.