J'essaie de faire une demande d'origine croisée en utilisant jquery mais elle continue d'être rejetée avec le message
XMLHttpRequest ne peut pas charger http: // ... Aucun en-tête 'Access-Control-Allow-Origin' n'est présent sur la ressource demandée. Origine ... n'est donc pas autorisé à accéder.
J'utilise flask, 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);
}
});
});
});
du côté heroku, j'utilise un flacon 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 __name__ == '__main__':
app.run()
curl
commandes. Maintenant, j'ai écrit une courte page html et j'essaie de faire une demande avec la méthode JS fetch () à mon API qui est basée sur Heroku et j'ai l'erreur CORS. Après avoir appliqué votre code, mon terminal a commencé à me répondre avec du code HTML (HTTP / 1.1 503 Service Unavailable) au lieu du JSON. Qu'est-ce qui pourrait être une erreur ici? Merci!!OK, je ne pense pas que l'extrait officiel mentionné par galuszkak devrait être utilisé partout, nous devrions nous préoccuper du cas où un bogue pourrait être déclenché pendant le gestionnaire tel que
hello_world
function. Que la réponse soit correcte ou incorrecte, l'en-Access-Control-Allow-Origin
tête est ce dont nous devons nous préoccuper. Donc, la chose est très simple, tout 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 ~~
la source
Je viens 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, alors voici mon approche pour ceux qui ne veulent pas compter sur plus de bibliothèques ou de décorateurs:
Une requête CORS se compose en fait de deux requêtes HTTP. Une demande de contrôle en amont, puis une demande réelle qui n'est effectuée que si le contrôle en amont réussit.
La demande de contrôle en amont
Avant la
POST
demande réelle de plusieurs domaines , le navigateur émettra uneOPTIONS
demande. Cette réponse ne doit renvoyer aucun corps, mais seulement quelques en-têtes rassurants indiquant au navigateur qu'il est correct de faire cette requête inter-domaines et que cela ne fait pas partie d'une attaque de script intersite.J'ai écrit une fonction Python pour construire cette réponse en utilisant la
make_response
fonction duflask
module.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 joker qui fonctionne pour toutes les demandes. Si vous souhaitez bénéficier de la sécurité supplémentaire obtenue 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'aller de l'avant et de faire la demande réelle.
La demande réelle
Lors du traitement de la demande réelle, vous devez ajouter un en-tête CORS, sinon le navigateur ne retournera pas la réponse au code JavaScript appelant. Au lieu de cela, la demande échouera du côté client. 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("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
la source
Si vous souhaitez activer CORS pour toutes les voies, puis il suffit d' installer flask_cors extension (
pip3 install -U flask_cors
) et enveloppeapp
comme ceci:CORS(app)
.C'est suffisant pour le faire (j'ai testé cela avec une
POST
demande de téléchargement d'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: s'il y a une erreur dans votre itinéraire, disons que vous essayez d'imprimer une variable qui n'existe pas, vous obtiendrez un message d'erreur CORS qui, en fait, n'a rien à voir avec CORS.
la source
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 __name__ == '__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
la source
Ma solution est un wrapper autour de 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(): ...
la source
Amélioration de la solution décrite ici: https://stackoverflow.com/a/52875875/10299604
Avec
after_request
nous pouvons gérer les en-têtes de réponse CORS en évitant d'ajouter du code supplémentaire à nos points de terminaison:### 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
la source
Toutes les réponses ci-dessus fonctionnent bien, mais vous obtiendrez probablement toujours une erreur CORS, si l'application renvoie une erreur que vous ne gérez pas, comme une erreur de clé, si vous ne faites pas correctement la validation d'entrée, par exemple. Vous pouvez ajouter un gestionnaire d'erreurs pour intercepter toutes les instances d'exceptions et ajouter des en-têtes de réponse CORS dans la réponse du serveur
Définissez donc un gestionnaire d'erreurs - 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
puis en utilisant la réponse de 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
la source
Si vous ne trouvez pas votre problème et que votre code devrait fonctionner, il se peut que votre requête n'atteigne que le temps maximum que Heroku vous permet de faire une requête. Heroku annule les demandes si cela prend plus de 30 secondes.
Référence: https://devcenter.heroku.com/articles/request-timeout
la source
J'ai résolu ce même problème en python en utilisant flask et avec cette bibliothèque. flask_cors
Référence: https://flask-cors.readthedocs.io/en/latest/
la source