Bagaimana mengaktifkan CORS di dalam labu

92

Saya mencoba membuat permintaan lintas asal menggunakan jquery tetapi terus ditolak dengan pesan

XMLHttpRequest tidak dapat memuat http: // ... Tidak ada header 'Access-Control-Allow-Origin' pada sumber yang diminta. Asal ... oleh karena itu tidak diizinkan akses.

Saya menggunakan flask, heroku, dan jquery

kode klien terlihat seperti ini:

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

di sisi heroku saya menggunakan termos dan seperti ini

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

Jawaban:

174

Inilah yang berhasil bagi saya ketika saya menerapkan ke Heroku.

http://flask-cors.readthedocs.org/en/latest/
Instal flask-cors dengan menjalankan - 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!"
Daniel Rasmuson
sumber
37
Ditambah 1 untuk halo dunia asal lintas!
Simon Nicholls
itu satu-satunya solusi yang berhasil untuk saya. Terima kasih!
psc37
2
Anda adalah penyelamat hidup! Bekerja seperti pesona.
Rohit Swami
Hai! Bisakah Anda membantu saya mencari tahu apa yang terjadi dalam kasus saya? Saya menulis API sederhana menggunakan Python / Flask, bahkan tanpa melihatnya. Saya mencapainya dengan curlperintah. Sekarang saya menulis halaman html pendek dan mencoba membuat permintaan dengan metode JS fetch () ke API saya yang berdasarkan Heroku dan saya mengalami kesalahan CORS. Setelah saya menerapkan kode Anda, terminal saya mulai merespons saya dengan kode HTML (Layanan HTTP / 1.1 503 Tidak Tersedia) alih-alih JSON. Apa yang mungkin menjadi kesalahan di sini? Terima kasih!!
Nikita Basharkin
5
Sebelum ada yang menyalin kode ini ke dalam aplikasi mereka, harap periksa dokumentasi karena hanya beberapa baris ini yang diperlukan.
rovyko
46

Oke, saya tidak berpikir potongan resmi yang disebutkan oleh galuszkak harus digunakan di mana-mana, kita harus memperhatikan kasus bahwa beberapa bug mungkin dipicu selama penangan seperti hello_worldfungsi. Apakah tanggapannya benar atau tidak, Access-Control-Allow-Origintajuk adalah yang harus kita perhatikan. Jadi, masalahnya sangat sederhana, seperti di bawah ini:

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

Itu semua ~~

zhangqy
sumber
Ini juga membantu saya untuk proyek kecil dengan operasi CRUD dasar. Tidak perlu sesuatu yang mewah, lewati saja kesalahannya :)
Narshe
34

Saya baru saja menghadapi masalah yang sama dan saya yakin bahwa jawaban lain sedikit lebih rumit daripada yang seharusnya, jadi inilah pendekatan saya untuk mereka yang tidak ingin bergantung pada lebih banyak perpustakaan atau dekorator:

Permintaan CORS sebenarnya terdiri dari dua permintaan HTTP. Permintaan preflight dan kemudian permintaan sebenarnya yang hanya dibuat jika preflight berhasil lolos.

Permintaan preflight

Sebelum POSTpermintaan lintas domain sebenarnya , browser akan mengeluarkanOPTIONS permintaan. Respons ini seharusnya tidak menampilkan isi apa pun, tetapi hanya beberapa tajuk yang meyakinkan yang memberi tahu browser bahwa tidak masalah melakukan permintaan lintas-domain ini dan itu bukan bagian dari beberapa serangan skripting lintas situs.

Saya menulis fungsi Python untuk membangun respons ini menggunakan make_responsefungsi dari flaskmodul.

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

Respons ini adalah karakter pengganti yang berfungsi untuk semua permintaan. Jika Anda menginginkan keamanan tambahan yang diperoleh CORS, Anda harus memberikan daftar asal, header, dan metode yang diizinkan.

Tanggapan ini akan meyakinkan browser (Chrome) Anda untuk melanjutkan dan melakukan permintaan yang sebenarnya.

Permintaan sebenarnya

Saat melayani permintaan sebenarnya, Anda harus menambahkan satu header CORS - jika tidak, browser tidak akan mengembalikan respons ke kode JavaScript yang menjalankan. Sebaliknya, permintaan tersebut akan gagal di sisi klien. Contoh dengan jsonify

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

Saya juga menulis fungsi untuk itu.

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

memungkinkan Anda mengembalikan satu baris.

Kode terakhir

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.
sumber
Terima kasih @Niels B. begitu banyak, Anda menghemat waktu saya. Saya telah menambahkan konfigurasi cors sebelumnya tetapi tidak mengaturnya dengan benar.
Günay Gültekin
1
Sejauh ini, ini adalah jawaban terbaik untuk masalah CORS di Flask. Bekerja seperti pesona! Terima kasih @Niels
Chandra Kanth
Terima kasih atas penjelasan Anda yang sangat detail !! Ini sangat membantu!
jones-chris
Gunakan banyak solusi, termasuk CORS dan milik Anda, tetapi semuanya tidak berfungsi untuk aws (ikuti contoh ini-- aws.amazon.com/getting-started/projects/… ), apakah ada yang tahu apa yang sedang terjadi?
StereoMatching
Solusi ini sangat sederhana namun elegan! Terima kasih, Anda benar-benar menghemat waktu saya.
Gerry
22

Jika Anda ingin mengaktifkan CORS untuk semua rute, kemudian hanya menginstal flask_cors ekstensi ( pip3 install -U flask_cors) dan bungkus appseperti ini: CORS(app).

Itu cukup untuk melakukannya (saya menguji ini dengan POSTpermintaan untuk mengunggah gambar, dan itu berhasil untuk saya):

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

Catatan penting: jika ada kesalahan dalam rute Anda, katakanlah Anda mencoba untuk mencetak variabel yang tidak ada, Anda akan mendapatkan pesan kesalahan terkait CORS yang sebenarnya tidak ada hubungannya dengan CORS.

Billal Begueradj
sumber
1
Terima kasih banyak! Solusi sederhana dan umum ini memungkinkan saya untuk memanggil API saya dari kode web React tanpa blok CORS lagi.
Sebastian Diaz
2
Terima kasih ! Bagian catatan penting menghemat banyak waktu saya.
Gabriel
4

Coba dekorator berikut:

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

Dekorator ini akan dibuat sebagai berikut:

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

Anda juga dapat melihat paket ini Flask-CORS

Newtt
sumber
masih tidak bekerja. Saya sudah mencobanya dan saya juga menggunakan paket Flask-CORS. Saya pikir Flask-CORS dibangun di atasnya
Lopes
3

Memperbaiki solusi yang dijelaskan di sini: https://stackoverflow.com/a/52875875/10299604

Dengan after_requestkita dapat menangani header respon CORS menghindari menambahkan kode ekstra ke endpoint kita:

    ### 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
Frank Escobar
sumber
2

Solusi saya adalah pembungkus 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():
    ...
yurzs
sumber
2

Semua tanggapan di atas berfungsi dengan baik, tetapi Anda mungkin masih akan mendapatkan kesalahan CORS, jika aplikasi menampilkan kesalahan yang tidak Anda tangani, seperti kesalahan kunci, jika Anda tidak melakukan validasi input dengan benar, misalnya. Anda dapat menambahkan penangan error untuk menangkap semua contoh pengecualian dan menambahkan header respons CORS di respons server

Jadi tentukan penangan kesalahan - 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

lalu gunakan jawaban 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 
Edrich
sumber
2

Saya menyelesaikan masalah yang sama ini dengan python menggunakan flask dan dengan perpustakaan ini. flask_cors

Referensi: https://flask-cors.readthedocs.io/en/latest/

pedro Orozco
sumber
Meskipun tautan ini mungkin menjawab pertanyaan, lebih baik menyertakan bagian penting dari jawaban di sini dan menyediakan tautan untuk referensi. Jawaban link saja bisa menjadi tidak valid jika halaman tertaut berubah. - Dari Ulasan
Jason Aller
0

Jika Anda tidak dapat menemukan masalah Anda dan kode Anda seharusnya berfungsi, mungkin permintaan Anda baru mencapai batas waktu maksimum yang diizinkan oleh heroku untuk membuat permintaan. Heroku membatalkan permintaan jika membutuhkan lebih dari 30 detik.

Referensi: https://devcenter.heroku.com/articles/request-timeout

Sampai
sumber