Ich versuche, eine jetzübergreifende Anfrage mit jquery zu stellen, diese wird jedoch weiterhin mit der Nachricht abgelehnt
XMLHttpRequest kann http: // ... nicht laden. In der angeforderten Ressource ist kein Header 'Access-Control-Allow-Origin' vorhanden. Origin ... ist daher kein Zugriff gestattet.
Ich benutze Flasche, Heroku und JQuery
Der Client-Code sieht folgendermaßen aus:
$(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);
}
});
});
});
Auf der Heroku-Seite benutze ich eine Flasche und es ist so
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
Befehle erreicht. Jetzt habe ich eine kurze HTML-Seite geschrieben und versucht, eine Anfrage mit der JS-Methode fetch () an meine API zu senden, die auf Heroku basiert, und ich habe den CORS-Fehler. Nachdem ich Ihren Code angewendet hatte, antwortete mein Terminal mit HTML-Code (HTTP / 1.1 503 Service nicht verfügbar) anstelle von JSON. Was könnte hier ein Fehler sein? Vielen Dank!!OK, ich denke nicht, dass das von galuszkak erwähnte offizielle Snippet überall verwendet werden sollte, wir sollten den Fall befürchten, dass während des Handlers ein Fehler ausgelöst wird, wie z. B. die
hello_world
Funktion. Unabhängig davon, ob die Antwort korrekt oder nicht korrektAccess-Control-Allow-Origin
ist, sollten wir uns um den Header kümmern. Die Sache ist also sehr einfach, genau wie unten:@blueprint.after_request # blueprint can also be app~~ def after_request(response): header = response.headers header['Access-Control-Allow-Origin'] = '*' return response
Das ist alles ~~
quelle
Ich habe mich gerade mit dem gleichen Problem konfrontiert und bin zu der Überzeugung gelangt, dass die anderen Antworten etwas komplizierter sind als nötig. Daher hier mein Ansatz für diejenigen, die sich nicht auf mehr Bibliotheken oder Dekorateure verlassen möchten:
Eine CORS-Anforderung besteht tatsächlich aus zwei HTTP-Anforderungen. Eine Preflight-Anfrage und dann eine tatsächliche Anfrage, die nur gestellt wird, wenn der Preflight erfolgreich bestanden wurde.
Die Preflight-Anfrage
Vor der eigentlichen domänenübergreifenden
POST
Anfrage gibt der Browser eineOPTIONS
Anfrage aus. Diese Antwort sollte keinen Text zurückgeben, sondern nur einige beruhigende Header, die dem Browser mitteilen, dass diese domänenübergreifende Anforderung in Ordnung ist und nicht Teil eines Cross-Site-Scripting-Angriffs ist.Ich habe eine Python-Funktion geschrieben, um diese Antwort mithilfe der
make_response
Funktion aus demflask
Modul zu erstellen .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
Diese Antwort ist ein Platzhalter, der für alle Anforderungen funktioniert. Wenn Sie die zusätzliche Sicherheit von CORS nutzen möchten, müssen Sie eine Whitelist mit Ursprüngen, Headern und Methoden bereitstellen.
Diese Antwort wird Ihren (Chrome) Browser davon überzeugen, die eigentliche Anfrage zu stellen.
Die eigentliche Anfrage
Wenn Sie die eigentliche Anfrage bearbeiten, müssen Sie einen CORS-Header hinzufügen. Andernfalls gibt der Browser die Antwort auf den aufrufenden JavaScript-Code nicht zurück. Stattdessen schlägt die Anforderung auf der Clientseite fehl. Beispiel mit jsonify
response = jsonify({"order_id": 123, "status": "shipped"} response.headers.add("Access-Control-Allow-Origin", "*") return response
Ich habe auch eine Funktion dafür geschrieben.
def _corsify_actual_response(response): response.headers.add("Access-Control-Allow-Origin", "*") return response
So können Sie einen Einzeiler zurückgeben.
Endgültiger Code
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
quelle
Wenn Sie CORS für alle Routen aktivieren möchten, installieren Sie einfach die Erweiterung flask_cors (
pip3 install -U flask_cors
) und wickeln Sie sieapp
wie folgt ein :CORS(app)
.Das reicht aus (ich habe dies mit der
POST
Aufforderung getestet , ein Bild hochzuladen, und es hat bei mir funktioniert):from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) # This will enable CORS for all routes
Wichtiger Hinweis: Wenn Ihre Route einen Fehler enthält, nehmen wir an, Sie versuchen, eine nicht vorhandene Variable zu drucken. Sie erhalten eine CORS-Fehlermeldung, die tatsächlich nichts mit CORS zu tun hat.
quelle
Probieren Sie die folgenden Dekorateure aus:
@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()
Dieser Dekorateur würde wie folgt erstellt:
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
Sie können sich auch dieses Paket Flask-CORS ansehen
quelle
Meine Lösung ist ein Wrapper um 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(): ...
quelle
Verbesserung der hier beschriebenen Lösung: https://stackoverflow.com/a/52875875/10299604
Mit können
after_request
wir die CORS-Antwortheader verarbeiten und vermeiden, unseren Endpunkten zusätzlichen Code hinzuzufügen:### 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
quelle
Alle oben genannten Antworten funktionieren einwandfrei, aber es wird wahrscheinlich immer noch ein CORS-Fehler angezeigt, wenn die Anwendung einen Fehler auslöst, den Sie nicht behandeln, wie z. B. einen Schlüsselfehler, wenn Sie beispielsweise die Eingabevalidierung nicht ordnungsgemäß durchführen. Sie können einen Fehlerhandler hinzufügen, um alle Instanzen von Ausnahmen abzufangen und der Serverantwort CORS-Antwortheader hinzuzufügen
Definieren Sie also einen Fehlerhandler - 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
dann mit Billals Antwort:
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
quelle
Wenn Sie Ihr Problem nicht finden können und Ihr Code funktionieren sollte, kann es sein, dass Ihre Anfrage gerade die maximale Zeit erreicht, die Heroku Ihnen erlaubt, eine Anfrage zu stellen. Heroku storniert Anfragen, wenn es länger als 30 Sekunden dauert.
Referenz: https://devcenter.heroku.com/articles/request-timeout
quelle
Ich habe das gleiche Problem in Python mit flask und mit dieser Bibliothek gelöst. flask_cors
Referenz: https://flask-cors.readthedocs.io/en/latest/
quelle