Lösen Sie die gemeinsame Nutzung von Cross Origin-Ressourcen mit Flask

81

Für die folgende ajaxPostanfrage für Flask( wie kann ich Daten verwenden, die von Ajax in der Flasche gepostet wurden? ):

$.ajax({
    url: "http://127.0.0.1:5000/foo", 
    type: "POST",
    contentType: "application/json",
    data: JSON.stringify({'inputVar': 1}),
    success: function( data ) { 
        alert( "success" + data );
    }   
});

Ich erhalte eine Cross Origin Resource Sharing (CORS)Fehlermeldung:

No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'null' is therefore not allowed access. 
The response had HTTP status code 500.

Ich habe versucht, es auf zwei Arten zu lösen, aber keine scheint zu funktionieren.

  1. Verwenden von Flask-CORS

Dies ist eine FlaskErweiterung für die Handhabung CORS, die originenspezifisches AJAX ermöglichen soll.

Mein pythonServer.py mit dieser Lösung:

from flask import Flask
from flask.ext.cors import CORS, cross_origin

app = Flask(__name__)
cors = CORS(app, resources={r"/foo": {"origins": "*"}})
app.config['CORS_HEADERS'] = 'Content-Type'

@app.route('/foo', methods=['POST','OPTIONS'])
@cross_origin(origin='*',headers=['Content-Type','Authorization'])
def foo():
    return request.json['inputVar']

if __name__ == '__main__':
    app.run()
  1. Verwendung eines bestimmten Kolbendekorateurs

Dies ist ein offizielles Flask-Code-Snippet, das einen Dekorateur definiert, der die CORSvon ihm dekorierten Funktionen berücksichtigen soll.

Mein pythonServer.py mit dieser Lösung:

from flask import Flask, make_response, request, current_app
from datetime import timedelta
from functools import update_wrapper

app = Flask(__name__)

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

@app.route('/foo', methods=['GET','POST','OPTIONS'])
@crossdomain(origin="*")
def foo():
    return request.json['inputVar']

if __name__ == '__main__':
    app.run()

Können Sie bitte einen Hinweis geben, warum das so ist?

Matteo
quelle
hast du herausgefunden Ich stoße auf genau das gleiche Problem :(
Shao
Dies ist eine alte Frage, aber nur um sicherzugehen: Haben Sie Ihren Flask-Server neu gestartet? Ich habe mich auch gefragt, warum ich den gleichen Fehler bekommen habe, obwohl ich dachte, dass alles genau so ist, wie sie sollten. Es stellte sich heraus, Sie haben den Server neu starten , um für sie wirklich wirksam zu
Juha Untinen

Antworten:

49

Es hat wie ein Champion funktioniert, nachdem Ihr Code etwas geändert wurde

# initialization
app = Flask(__name__)
app.config['SECRET_KEY'] = 'the quick brown fox jumps over the lazy   dog'
app.config['CORS_HEADERS'] = 'Content-Type'

cors = CORS(app, resources={r"/foo": {"origins": "http://localhost:port"}})

@app.route('/foo', methods=['POST'])
@cross_origin(origin='localhost',headers=['Content- Type','Authorization'])
def foo():
    return request.json['inputVar']

if __name__ == '__main__':
   app.run()

Ich habe * durch localhost ersetzt. Da ich in vielen Blogs und Posts gelesen habe, sollten Sie den Zugriff für eine bestimmte Domain zulassen

Satish
quelle
2
Wenn jemand Blaupausen verwendet, müssen Sie jedem Blaupause das CORS () hinzufügen, zum Beispiel: my_blueprint = Blueprint ('mein_bp_name', Name , url_prefix = "/ mein-Präfix") CORS (my_blueprint)
BLang
88

Sie können die Ergebnisse mit einem einfachen erhalten:

@app.route('your route', methods=['GET'])
def yourMethod(params):
    response = flask.jsonify({'some': 'data'})
    response.headers.add('Access-Control-Allow-Origin', '*')
    return response
Salvador Dali
quelle
1
Besser als das Hinzufügen einer domänenübergreifenden Implementierung!
Florescu Cătălin
Einfach und effektiv
Anthony
4
Brillant! Ich stimme zu, einfach und effektiv. IMO sollte Antwort akzeptiert werden
PALEN
3
@Salvador Dali - Wissen Sie, wie Cross Origin richtig zugelassen werden kann, wenn ich eine Vorlage anstelle eines JSON-Objekts rendere? dh letzte Codezeile in yourMethodist:return render_template('template.html',some_var = response)
Matteo
3
Könnte dies in einer Post-Methode verwendet werden? Ich habe versucht, eine Datei hochzuladen, und bin fehlgeschlagen.
W.Leto
60

Nun, ich stand vor dem gleichen Problem. Für neue Benutzer, die möglicherweise auf dieser Seite landen. Folgen Sie einfach ihren offiziellen Unterlagen.

Installieren Sie die Kolben

pip install -U flask-cors

Initialisieren Sie dann nach der App-Initialisierung flask-corsmit Standardargumenten:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
   return "Hello, cross-origin-world!"
Nagashayan
quelle
Dies führt für mich zu folgendem Fehler: Der Zugriff auf XMLHttpRequest unter 'my_domain' vom Ursprung ' 127.0.0.1:5000 ' wurde durch die CORS-Richtlinie blockiert: Die Antwort auf die Preflight-Anforderung besteht die Zugriffssteuerungsprüfung nicht: Die 'Access-Control-Allow- Der Origin-Header enthält mehrere Werte ' 127.0.0.1:5000 , *', aber nur einer ist zulässig.
bescheidenPilgrim
Funktioniert bei mir nicht stackoverflow.com/questions/59652099/…
WP McNeill
Funktioniert auch bei mir Tks!
Jose
Hat für mich gearbeitet! Vielen Dank :)
XpressGeek
wie eingestellt Access-Control-Max-Agefür flask_cors?
DragonKnight
5

Könnte auch eine Antwort sein. Ich hatte heute das gleiche Problem und es war eher kein Problem als erwartet. Die CORS - Funktionalität Nach dem Hinzufügen Sie müssen Ihren Flask - Server neu starten ( ctrl + c-> python manage.py runserveroder Egal welche Methode Sie verwenden)), um die Änderung zu übernehmen, auch wenn der Code korrekt ist. Andernfalls funktioniert das CORS in der aktiven Instanz nicht.

So sieht es für mich aus und es funktioniert (Python 3.6.1, Flask 0.12):

factory.py :

from flask import Flask
from flask_cors import CORS  # This is the magic


def create_app(register_stuffs=True):
    """Configure the app and views"""
    app = Flask(__name__)
    CORS(app)  # This makes the CORS feature cover all routes in the app

    if register_stuffs:
        register_views(app)
    return app


def register_views(app):
    """Setup the base routes for various features."""
    from backend.apps.api.views import ApiView
    ApiView.register(app, route_base="/api/v1.0/")

views.py :

from flask import jsonify
from flask_classy import FlaskView, route


class ApiView(FlaskView):
    @route("/", methods=["GET"])
    def index(self):
        return "API v1.0"

    @route("/stuff", methods=["GET", "POST"])
    def news(self):
        return jsonify({
            "stuff": "Here be stuff"
        })

In meiner React App console.log:

Sending request:
GET /stuff
With parameters:
null
bundle.js:17316 Received data from Api:
{"stuff": "Here be stuff"}
Juha Untinen
quelle
4

Beachten Sie, dass das Festlegen des Access-Control-Allow-OriginHeaders im Flask-Antwortobjekt in vielen Fällen in Ordnung ist (z. B. in diesem Fall), jedoch keine Auswirkungen auf die Bereitstellung statischer Assets hat (zumindest in einem Produktionssetup). Dies liegt daran, dass statische Assets direkt vom nach vorne gerichteten Webserver (normalerweise Nginx oder Apache) bereitgestellt werden. In diesem Fall müssen Sie den Antwortheader auf Webserverebene und nicht in Flask festlegen.

Weitere Informationen finden Sie in diesem Artikel, den ich vor einiger Zeit geschrieben habe und in dem erläutert wird, wie die Header festgelegt werden (in meinem Fall habe ich versucht, die domänenübergreifende Bereitstellung von Font Awesome-Assets durchzuführen).

Wie bei @Satu bereits erwähnt, müssen Sie bei JS AJAX-Anforderungen möglicherweise nur den Zugriff für eine bestimmte Domäne zulassen. Ich denke, dass das Anfordern statischer Assets (wie Schriftdateien) weniger streng ist und das Zulassen des Zugriffs für jede Domain mehr akzeptiert wird.

Jaza
quelle
3

Ich habe einen Dekorateur von Armin Ronacher mit kleinen Änderungen verwendet (aufgrund unterschiedlicher Header, die vom Kunden angefordert werden). Und das hat bei mir funktioniert. (wo ich Angular als Anforderer verwende, der die Anwendung / den JSON-Typ anfordert).

Der Code wird an den folgenden Stellen leicht geändert.

from flask import jsonify

@app.route('/my_service', methods=['POST', 'GET','OPTIONS'])
@crossdomain(origin='*',headers=['access-control-allow-origin','Content-Type'])
def my_service():
    return jsonify(foo='cross domain ftw')

jsonify sendet eine Anwendung / einen json-Typ, andernfalls ist es text / html. Header werden als Client in meiner Fallanforderung für diese Header hinzugefügt

 const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin':'*'
      })
    };
    return this.http.post<any>(url, item,httpOptions)
D. Waasala
quelle
2
Die Verbindung zum Dekorateur ist tot
José Tomás Tocino
2

Hinweis: Die Platzierung von cross_origin sollte stimmen und Abhängigkeiten werden installiert. Stellen Sie auf der Clientseite sicher, dass Sie angeben, welche Art von Datenserver verwendet wird. Zum Beispiel application / json oder text / html

Für mich war der unten geschriebene Code magisch

from flask import Flask,request,jsonify
from flask_cors import CORS,cross_origin
app=Flask(__name__)
CORS(app, support_credentials=True)
@app.route('/api/test', methods=['POST', 'GET','OPTIONS'])
@cross_origin(supports_credentials=True)
def index():
    if(request.method=='POST'):
     some_json=request.get_json()
     return jsonify({"key":some_json})
    else:
        return jsonify({"GET":"GET"})


if __name__=="__main__":
    app.run(host='0.0.0.0', port=5000)
Dila Gurung
quelle
Warum machst du dasselbe (support_credentials = True) in cross_origin?
Eziz Durdyyev
0

Ich hatte viel mit etwas Ähnlichem zu kämpfen. Versuche Folgendes:

  1. Verwenden Sie eine Art Browser-Plugin, das die HTML-Header anzeigen kann.
  2. Geben Sie die URL zu Ihrem Dienst ein und zeigen Sie die zurückgegebenen Header-Werte an.
  3. Stellen Sie sicher, dass Access-Control-Allow-Origin auf eine und nur eine Domäne festgelegt ist, die der Anforderungsursprung sein sollte. Setzen Sie Access-Control-Allow-Origin nicht auf *.

Wenn dies nicht hilft, lesen Sie diesen Artikel. Es ist auf PHP, aber es beschreibt genau, welche Header auf welche Werte gesetzt werden müssen, damit CORS funktioniert.

CORS, die in IE, Firefox, Chrome und Safari funktionieren

Per Kristian
quelle
0

Ich bin vielleicht zu spät bei dieser Frage, aber die folgenden Schritte haben das Problem behoben

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)
Ramkumar Khubchandani
quelle