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()
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!"
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 ~~
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
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:
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
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.