web-dev-qa-db-fra.com

Comment activer CORS en flacon et heroku

J'essaie de faire une requête cross origine à l'aide de jQuery, mais le message continue à être rejeté. 

XMLHttpRequest ne peut pas charger http: // ... Non 'Access-Control-Allow-Origin' l'en-tête est présent sur la ressource demandée. L'origine ... est donc accès non autorisé.

J'utilise fiole, heroku et jquery 

le code client ressemble à ceci:

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

côté heroku, j'utilise un ballon et c'est comme ça

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 __== '__main__':
    app.run()
26
Lopes

Voici ce qui a fonctionné pour moi lors de mon déploiement à 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!"
59
Daniel Rasmuson

OK, je ne pense pas que l'extrait de code officiel mentionné par galuszkak devrait être utilisé partout, nous devrions nous inquiéter au cas où un bogue pourrait être déclenché lors du gestionnaire, tel que la fonction hello_world. Que la réponse soit correcte ou non correcte, l'en-tête Access-Control-Allow-Origin est ce qui devrait nous préoccuper. Donc, la chose est très simple, juste comme ci-dessous:

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

C'est tout ~~

15
zhangqy

Essayez les décorateurs suivants:

@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 __== '__main__':
    app.run()

Ce décorateur serait créé comme suit: 

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

Vous pouvez également consulter ce package Flask-CORS

2
Newtt

Je viens juste de faire face au même problème et j'en suis venu à croire que les autres réponses sont un peu plus compliquées qu'elles ne devraient l'être, donc pour ceux qui ne veulent pas compter sur plus de bibliothèques ou de décorateurs. Voici mon approche:

Le preflight

Avant la requête _POST interdomaine réelle, le navigateur émettra une demande OPTIONS. Cette réponse ne doit renvoyer aucun corps, mais seulement quelques en-têtes rassurantes indiquant au navigateur qu'il doit déjà faire cette demande interdomaine et qu'il ne fait pas partie d'une attaque de script intersite.

J'ai écrit une fonction Python pour générer cette réponse à l'aide de la fonction make_response du module 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

Cette réponse est un caractère générique qui fonctionne pour toutes les demandes. Si vous souhaitez bénéficier de la sécurité supplémentaire gagnée par CORS, vous devez fournir une liste blanche des origines, des en-têtes et des méthodes.

Cette réponse convaincra votre navigateur (Chrome) d’exécuter la demande.

Cependant, pour lire les données renvoyées par la réponse réelle, vous devez ajouter un en-tête cors - sinon, le navigateur le bloque. Exemple avec jsonify

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

J'ai aussi écrit une fonction pour ça.

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

vous permettant de retourner un one-liner.

Code final:

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
1
Niels B.

Si vous souhaitez activer CORS pour toutes les routes, installez simplement flask_cors extension (pip3 install -U flask_cors) et enveloppez app comme ceci: CORS(app).

C’est suffisant pour le faire (j’ai testé cela avec une requête POST pour télécharger une image, et cela a fonctionné pour moi):

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

Remarque importante: en cas d'erreur dans votre itinéraire, si vous essayez d'imprimer une variable inexistante, vous obtiendrez un message lié à une erreur CORS qui, en réalité, n'a rien à voir avec CORS.

0
Billal Begueradj