web-dev-qa-db-fra.com

Résoudre le partage de ressources d’origine croisée avec Flask

Pour la demande suivante ajax post pour Flask ( comment puis-je utiliser les données postées depuis ajax dans une fiole? ):

$.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 );
    }   
});

Je reçois un Cross Origin Resource Sharing (CORS) erreur:

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.

J'ai essayé de le résoudre de deux manières, mais aucune ne semble fonctionner.

  1. Utilisation de Flask-CORS

Il s’agit d’une extension Flask pour la gestion de CORS qui devrait permettre l’origine croisée AJAX).

Mon pythonServer.py en utilisant cette solution:

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 __== '__main__':
    app.run()
  1. Utilisation spécifique Flask Decorator

Ceci est un extrait de code officiel Flask) définissant un décorateur devant autoriser CORS sur les fonctions qu’il décore.

Mon pythonServer.py en utilisant cette solution:

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 __== '__main__':
    app.run()

Pouvez-vous s'il vous plaît donner quelques indications sur la raison?

55
Matteo

Cela a fonctionné comme un champion, après modification mineure de votre code

# 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 __== '__main__':
   app.run()

J'ai remplacé * par localhost. Comme je l'ai lu dans de nombreux blogs et publications, vous devez autoriser l'accès à un domaine spécifique.

31
Satish

Vous pouvez obtenir les résultats avec un simple:

@app.route('your route', methods=['GET'])
def yourMethod(params):
    response = flask.jsonify({'some': 'data'})
    response.headers.add('Access-Control-Allow-Origin', '*')
    return response
51
Salvador Dali

Eh bien, j'ai fait face au même problème. Pour les nouveaux utilisateurs qui peuvent atterrir sur cette page. Il suffit de suivre leur documentation officielle.

Installer des flacons

pip install -U flask-cors

puis après l'initialisation de l'application, initialisez flask-cors avec arguments par défaut:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
   return "Hello, cross-Origin-world!"
36
Nagashayan

Notez que le réglage de la Access-Control-Allow-Origin en-tête dans l'objet réponse Flask) convient dans de nombreux cas (comme celui-ci), mais cela n'a aucun effet lors de la gestion d'actifs statiques (dans une configuration de production, du moins). Les ressources statiques sont gérées directement par le serveur Web frontal (généralement Nginx ou Apache). Dans ce cas, vous devez définir l'en-tête de la réponse au niveau du serveur Web et non dans Flask.

Pour plus de détails, voir cet article que j'ai écrit il y a quelque temps, expliquant comment définir les en-têtes (dans mon cas, j'essayais de servir la distribution inter-domaines d'actifs Font Awesome).

En outre, comme @Satu l'a dit, vous devrez peut-être autoriser l'accès uniquement à un domaine spécifique, dans le cas de demandes JS AJAX. Pour les demandes d'actifs statiques (comme les fichiers de polices), je pense que les règles sont moins strictes, et permettre l’accès à n’importe quel domaine est plus accepté.

3
Jaza

Autant en faire une réponse. J'ai eu le même problème aujourd'hui et c'était plus un non-problème que prévu. Après avoir ajouté la fonctionnalité CORS, vous devez redémarrer votre Flask serveur (ctrl + c -> python manage.py runserver, ou quelle que soit la méthode utilisée))) pour que la modification soit prise en compte, même si le code est correct. Sinon, le CORS ne fonctionnera pas dans l'instance active.

Voici à quoi ça ressemble pour moi et cela fonctionne (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"
        })

Dans mon React app console.log:

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

J'ai utilisé décorateur donné par Armin Ronacher avec peu de modifications (en raison des en-têtes différents demandés par le client). Et cela a fonctionné pour moi. (où j'utilise angular comme demandeur demandant le type d'application/json).

Le code est légèrement modifié aux endroits ci-dessous,

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 enverra un type application/json, sinon ce sera text/html. les en-têtes sont ajoutés en tant que client dans ma demande de cas pour ces en-têtes

 const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin':'*'
      })
    };
    return this.http.post<any>(url, item,httpOptions)
2
D.Wasala

Remarque: L'emplacement de cross_Origin doit être correct et les dépendances sont installées. Du côté du client, assurez-vous de spécifier le type de consommation du serveur de données. Par exemple application/json ou text/html

Pour moi, le code écrit ci-dessous était magique

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)
0
Dila Gurung

J'ai beaucoup lutté avec quelque chose de similaire. Essayez ce qui suit:

  1. Utilisez une sorte de plug-in de navigateur pouvant afficher les en-têtes HTML.
  2. Entrez l'URL de votre service et affichez les valeurs d'en-tête renvoyées.
  3. Assurez-vous que Access-Control-Allow-Origin est défini sur un et un seul domaine, qui doit être l'origine de la demande. Ne définissez pas Access-Control-Allow-Origin sur *.

Si cela ne vous aide pas, jetez un oeil à cet article. C'est sur PHP, mais il décrit exactement quels en-têtes doivent être définis sur quelles valeurs pour que CORS fonctionne.

CORS qui fonctionne dans IE, Firefox, Chrome et Safari

0
PerKristian