Şişede CORS nasıl etkinleştirilir


92

Jquery kullanarak çapraz kaynak isteği yapmaya çalışıyorum ancak mesajla reddedilmeye devam ediyor

XMLHttpRequest http: // ... yükleyemiyor İstenen kaynakta 'Access-Control-Allow-Origin' başlığı yok. Menşe ... bu nedenle erişime izin verilmez.

Flask, heroku ve jquery kullanıyorum

müşteri kodu şöyle görünür:

$(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 tarafında şişeyi kullanıyorum ve bunun gibi

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

Yanıtlar:


174

İşte Heroku'ya konuşlandırıldığımda benim için işe yarayan şey.

http://flask-cors.readthedocs.org/en/latest/
Flask-cors'u çalıştırarak kurun - 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!"

37
Merhaba çapraz kökenli dünya için artı 1!
Simon Nicholls

benim için işe yarayan tek çözüm buydu. Teşekkürler!
psc37

2
Sen bir hayat kurtarıcısın! Bir cazibe gibi çalıştı.
Rohit Swami

Selam! Benim durumumda ne olacağını anlamama yardım eder misin? Python / Flask kullanarak, bir görünüm bile olmadan basit bir API yazdım. Ona curlkomutlarla ulaştım . Şimdi kısa bir html sayfası yazdım ve Heroku'ya dayalı API'ime JS fetch () yöntemi ile istek yapmaya çalışıyorum ve CORS hatası aldım. Kodunuzu uyguladıktan sonra, terminalim JSON yerine HTML kodu (HTTP / 1.1 503 Hizmet Kullanılamıyor) ile bana yanıt vermeye başladı. Burada hata ne olabilir? Teşekkür ederim!!
Nikita Basharkin

5
Herhangi biri bu kodu uygulamasına kopyalamadan önce, lütfen belgelere bakın, çünkü bu satırlardan sadece bazıları gereklidir.
rovyko

46

Tamam, galuszkak'ın bahsettiği resmi pasajın her yerde kullanılması gerektiğini düşünmüyorum, hello_worldişlev gibi bazı hataların işleyici sırasında tetiklenebileceğini düşünmeliyiz . Yanıt ister doğru ister yanlış olsun, Access-Control-Allow-Originilgilendiğimiz konu başlıktır. Yani, aşağıdaki gibi çok basit:

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

Hepsi bu kadar ~~


Bu aynı zamanda temel CRUD operasyonları olan küçük bir proje için bana yardımcı oldu. Süslü bir şeye gerek yok, sadece hatayı
atlayın

34

Aynı sorunla daha yeni karşılaştım ve diğer cevapların olması gerekenden biraz daha karmaşık olduğuna inandım, işte bu yüzden daha fazla kütüphaneye veya dekoratöre güvenmek istemeyenler için yaklaşımım:

Bir CORS isteği aslında iki HTTP isteğinden oluşur. Bir ön kontrol isteği ve ardından yalnızca ön kontrol başarıyla geçerse yapılan gerçek bir istek.

Ön kontrol talebi

Gerçek etki alanları arası POSTistekten önce, tarayıcı bir OPTIONSistek gönderecektir. Bu yanıt herhangi bir gövde döndürmemeli, yalnızca tarayıcıya bu etki alanları arası isteği yapmanın uygun olduğunu ve bunun siteler arası komut dosyası yazma saldırısının bir parçası olmadığını söyleyen bazı güven verici başlıklar döndürmelidir.

Bu yanıtı modüldeki make_responseişlevi kullanarak oluşturmak için bir Python işlevi yazdım 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

Bu yanıt, tüm istekler için çalışan bir joker karakterdir. CORS tarafından kazanılan ek güvenliği istiyorsanız, kökenler, başlıklar ve yöntemlerden oluşan bir beyaz liste sağlamanız gerekir.

Bu yanıt, (Chrome) tarayıcınızı devam etmeye ve asıl isteği yerine getirmeye ikna edecektir.

Asıl istek

Gerçek isteği sunarken, bir CORS başlığı eklemeniz gerekir - aksi takdirde tarayıcı, çağrılan JavaScript koduna yanıtı döndürmez. Bunun yerine istek, istemci tarafında başarısız olacaktır. Jsonify ile örnek

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

Bunun için de bir fonksiyon yazdım.

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

tek satırlık bir geri dönüş yapmanıza izin verir.

Nihai kod

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

@Niels B. çok teşekkürler, zamanımı kurtardın. Daha önce cors yapılandırmasını ekledim ancak doğru şekilde ayarlamadım.
Günay Gültekin

1
Bu, Flask'taki bu CORS sorunu için açık ara en iyi cevap. Büyü gibi çalıştı! Teşekkürler @Niels
Chandra Kanth

Çok detaylı açıklamanız için teşekkür ederiz !! Bu çok yardımcı oldu!
jones-chris

CORS ve sizinki de dahil olmak üzere birçok çözümü kullanın, ancak hepsi aws için çalışmıyor (bu örneği izleyin - aws.amazon.com/getting-started/projects/… ), neler olduğunu bilen var mı?
StereoMatching

Bu çözüm gerçekten basit ama şık! Teşekkürler, gerçekten zamanımı kurtardın.
Gerry

22

Tüm yollar için CORS'yi etkinleştirmek istiyorsanız, o zaman sadece yüklemek flask_cors uzantısı ( pip3 install -U flask_cors) ve wrap appböyle: CORS(app).

Bunu yapmak için yeterli (bunu POSTbir resim yükleme isteği ile test ettim ve benim için çalıştı):

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

Önemli not: Rotanızda bir hata varsa, var olmayan bir değişkeni yazdırmaya çalıştığınızı varsayalım, aslında CORS ile hiçbir ilgisi olmayan bir CORS hatasıyla ilgili mesaj alacaksınız.


1
Çok teşekkürler! Bu basit ve genel çözüm, API'mi artık CORS bloğu olmadan React web kodumdan çağırmama izin verdi.
Sebastian Diaz

2
Teşekkür ederim ! Önemli not kısmı bana epey zaman kazandırdı.
Gabriel

4

Aşağıdaki dekoratörleri deneyin:

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

Bu dekoratör şu şekilde yaratılacaktır:

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

Ayrıca bu Flask-CORS paketine de göz atabilirsiniz.


hala çalışmıyor. Bunu zaten denedim ve Flask-CORS paketini de kullandım. Sanırım Flask-CORS bunun üzerine inşa edildi
Lopes

3

Burada açıklanan çözümü iyileştirme: https://stackoverflow.com/a/52875875/10299604

İle after_request, uç noktalarımıza ekstra kod eklemekten kaçınarak CORS yanıt başlıklarını idare edebiliriz:

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

2

Çözümüm app.route etrafında bir sarmalayıcı:

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

Yukarıdaki tüm yanıtlar sorunsuz çalışır, ancak, örneğin, girdi doğrulamasını düzgün yapmıyorsanız, uygulama bir anahtar hatası gibi işlemediğiniz bir hata atarsa, muhtemelen bir CORS hatası alırsınız. Tüm istisna örneklerini yakalamak için bir hata işleyici ekleyebilir ve sunucu yanıtına CORS yanıt başlıkları ekleyebilirsiniz.

Bu nedenle bir hata işleyicisi tanımlayın - 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

sonra Billal'ın cevabını kullanarak :

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 


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.