J'ai besoin d'envoyer des données via XmlHttpRequest
depuis JavaScript vers Python. Comme j'utilise localhost, je dois utiliser CORS . J'utilise le framework Flask et son module flask_cors
.
En JavaScript, j'ai ceci:
var xmlhttp;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
}
else {// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("POST", "http://localhost:5000/signin", true);
var params = "email=" + email + "&password=" + password;
xmlhttp.onreadystatechange = function() {//Call a function when the state changes.
if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
alert(xmlhttp.responseText);
}
}
xmlhttp.send(params);
et Python code:
@app.route('/signin', methods=['POST'])
@cross_Origin()
def sign_in():
email = cgi.escape(request.values["email"])
password = cgi.escape(request.values["password"])
Mais quand je l'exécute, je reçois ce message:
XMLHttpRequest ne peut pas charger localhost: 5000/signin. Aucun en-tête 'Access-Control-Allow-Origin' n'est présent sur la ressource demandée. Origin 'null' n'est donc pas autorisé à accéder.
Comment dois-je le réparer? Je sais que j'ai besoin d'utiliser un en-tête "Access-Control-Allow-Origin" mais je ne sais pas comment l'implémenter dans ce code. En passant, je dois utiliser du JavaScript pur.
J’ai utilisé Javascript avec Flask en utilisant ceci décorateur , et en ajoutant "OPTIONS" à ma liste de méthodes acceptables. Le décorateur doit être utilisé sous votre décorateur de route, comme cette:
@app.route('/login', methods=['POST', 'OPTIONS'])
@crossdomain(Origin='*')
def login()
...
Edit: Le lien semble être rompu. Voici le décorateur que j'ai utilisé.
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):
"""Decorator function that allows crossdomain requests.
Courtesy of
https://blog.skyred.fi/articles/better-crossdomain-snippet-for-flask.html
"""
if methods is not None:
methods = ', '.join(sorted(x.upper() for x in methods))
# use str instead of basestring if using Python 3.x
if headers is not None and not isinstance(headers, basestring):
headers = ', '.join(x.upper() for x in headers)
# use str instead of basestring if using Python 3.x
if not isinstance(Origin, basestring):
Origin = ', '.join(Origin)
if isinstance(max_age, timedelta):
max_age = max_age.total_seconds()
def get_methods():
""" Determines which methods are allowed
"""
if methods is not None:
return methods
options_resp = current_app.make_default_options_response()
return options_resp.headers['allow']
def decorator(f):
"""The decorator function
"""
def wrapped_function(*args, **kwargs):
"""Caries out the actual cross domain code
"""
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)
h['Access-Control-Allow-Credentials'] = 'true'
h['Access-Control-Allow-Headers'] = \
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
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
J'ai utilisé l'extension flask-cors.
Installez en utilisant pip install flask-cors
Alors c'est simplement
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
Cela permettra à tous les domaines
Vieille question, mais pour les futurs googleurs avec ce problème, je l'ai résolu (et quelques autres problèmes en aval concernant CORS) pour mon application reposante en ajoutant ce qui suit à mon fichier app.py:
app = Flask(__name__)
api = Api(app)
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return response
if __== '__main__':
app.run()
Lorsque vous utilisez python 2.7
app = Flask(__name__)
api = Api(app)
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return response
if __== '__main__':
app.run()
Si vous utilisez python3 ou une version ultérieure, installez flask-cors en utilisant la commande pip install flask-cors
Le ajouter ce qui suit:
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
Il y a en fait un extrait brillant sur le site Flask pour modifier le Access-Control-Allow-Origin
en-tête côté serveur. http://flask.pocoo.org/snippets/56/
Vous avez le moyen facile de sortir de là, qui consiste à permettre à chaque *
domaine pour accéder à votre URL ou spécifiez votre sélection d’URL dans l’en-tête.
Dans ce cas, le serveur répond par un
Access-Control-Allow-Origin: *
ce qui signifie que n'importe quel domaine peut accéder à la ressource de manière intersite. Si les propriétaires de ressources de http: //bar.other souhaitaient restreindre l'accès à la ressource uniquement à partir de http: //foo.example , ils renverraient:Access-Control-Allow-Origin: http://foo.example
.
J'ai utilisé la solution de Zachary. Fonctionne bien.
Pour ceux qui se demandent où placer le nouveau décorateur:
Il suffit de copier le code du lien fourni par Zachary et de le placer dans un .py
fichier
Placez-le dans le dossier où se trouvent vos python (varie en fonction du système que vous utilisez et du fait que vous utilisiez ou non un environnement virtuel).
Dans votre flask), importez la méthode crossdomain
à partir du module python) nouvellement créé et utilisez-la.
Le Access-Control-Allow-Origin doit être envoyé par le serveur, pas par vous. Lorsque vous appelez un autre domaine, le navigateur vérifie si cet en-tête est renvoyé par le serveur. Si ce n'est pas le cas, l'appel échoue. Je ne connais pas Python, je ne sais donc pas comment faire en sorte que votre serveur envoie cet en-tête, ni même si vous pouvez modifier le serveur.