Rozwiązanie Cross Origin Resource Sharing with Flask

Na następujący ajax wniosek o Flask (Jak mogę wykorzystać dane wysłane z ajax w flask?):

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

I get a Cross Origin Resource Sharing (CORS) błąd:

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.

Próbowałem rozwiązać go na dwa następujące sposoby, ale żaden nie wydaje się działać.

  1. Korzystanie z kolby-CORS

Jest to rozszerzenie Flask do obsługi CORS, które powinno tworzyć AJAX możliwe.

Mój pythonServer.py użycie tego rozwiązania:

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. korzystanie ze specjalnej kolby Dekorator

To jest oficjalny fragment kodu kolby definiujący dekorator, który powinien zezwalać CORS na funkcje, które dekoruje.

Mój pythonServer.py użycie tego rozwiązania:

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()

Proszę. dać jakieś wskazówki, dlaczego tak jest?

Author: Community, 2014-11-17

9 answers

To działało jak champ, po bitowej modyfikacji kodu

# 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()

Zastąpiłem * przez localhost. Ponieważ, jak czytałem w wielu blogach i postach, powinieneś zezwolić na dostęp dla określonej domeny

 53
Author: Satish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-09 18:42:59

Możesz uzyskać wyniki za pomocą prostego:

@app.route('your route', methods=['GET'])
def yourMethod(params):
    response = flask.jsonify({'some': 'data'})
    response.headers.add('Access-Control-Allow-Origin', '*')
    return response
 93
Author: Salvador Dali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-12 23:27:29

Cóż, stanąłem przed tym samym problemem. Dla nowych użytkowników, którzy mogą wylądować na tej stronie. Po prostu postępuj zgodnie z ich oficjalną dokumentacją.

Install flask-cors

pip install -U flask-cors

Następnie po inicjalizacji aplikacji inicjalizuj flask-cors z domyślnymi argumentami:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
   return "Hello, cross-origin-world!"
 65
Author: Nagashayan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-12 16:45:57

Równie dobrze może to być odpowiedź. Miałem ten sam problem dzisiaj i to było bardziej nie-problem niż oczekiwano. Po dodaniu funkcji CORS, musisz ponownie uruchomić serwer Flask (ctrl + c -> python manage.py runserver, lub którąkolwiek z metod)), aby zmiana weszła w życie, nawet jeśli kod jest poprawny. W przeciwnym razie CORS nie będzie działać w aktywnej instancji.

Oto Jak to dla mnie wygląda i działa (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"
        })

W mojej konsoli aplikacji React.log:

Sending request:
GET /stuff
With parameters:
null
bundle.js:17316 Received data from Api:
{"stuff": "Here be stuff"}
 5
Author: Juha Untinen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-06 22:31:19

Zauważ, że ustawienie nagłówka Access-Control-Allow-Origin w obiekcie odpowiedzi Flask jest w wielu przypadkach dobre (np. ten), ale nie ma żadnego wpływu na obsługę zasobów statycznych (przynajmniej w konfiguracji produkcyjnej). Dzieje się tak dlatego, że zasoby statyczne są obsługiwane bezpośrednio przez frontowy serwer WWW (zwykle Nginx lub Apache). W takim przypadku musisz ustawić nagłówek odpowiedzi na poziomie serwera www, a nie w Flask.

Aby uzyskać więcej szczegółów, zobacz ten artykuł, który napisałem jakiś czas temu, wyjaśniając, jak ustawić nagłówki (w moim przypadku próbowałem obsługiwać zasoby Font Awesome w różnych domenach).

Również, jak powiedział @Satu, może być konieczne zezwolenie dostępu tylko dla określonej domeny, w przypadku żądań JS AJAX. W przypadku żądania zasobów statycznych (takich jak pliki czcionek), myślę, że reguły są mniej rygorystyczne, a Zezwolenie na dostęp dla dowolnej domeny jest bardziej akceptowane.

 4
Author: Jaza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-12 05:24:10

Użyłem dekoratora podanego przez Armina Ronachera z niewielkimi modyfikacjami (z powodu różnych nagłówków, które są wymagane przez Klienta).I to mi pomogło. (gdzie używam angular jako requester requesting application / json type).

Kod jest nieco zmodyfikowany w poniższych miejscach,

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 wyśle typ aplikacji / json, w przeciwnym razie będzie to tekst / html. nagłówki są dodawane jako klient w moim przypadku żądanie dla tych nagłówków

 const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin':'*'
      })
    };
    return this.http.post<any>(url, item,httpOptions)
 3
Author: D.Waasala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-02 23:21:46

Mogę się spóźnić na to pytanie, ale poniżej kroków Naprawiono problem

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)
 3
Author: Ramkumar Khubchandani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-03 06:25:46

Uwaga: umieszczenie cross_origin powinno być prawidłowe i zainstalowane są zależności. Po stronie klienta, upewnij się, aby określić rodzaj serwera danych jest zużywa. Na przykład application/json lub text / html

Dla mnie kod napisany poniżej zrobił magię

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)
 2
Author: Dila Gurung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-11 11:40:25

Walczyłem z czymś podobnym. Spróbuj:

  1. Użyj wtyczki do przeglądarki, która może wyświetlać nagłówki HTML.
  2. Wprowadź adres URL do usługi i wyświetl zwrócone wartości nagłówka.
  3. Upewnij się, że Access-Control-Allow-Origin jest ustawione na jedną i tylko jedną domenę, która powinna być request origin. Nie ustawiaj Access-Control-Allow-Origin na *.

Jeśli to nie pomoże, spójrz na ten artykuł. Jest na PHP, ale opisuje dokładnie, które nagłówki muszą być ustawione, na które wartości mają działać CORS.

CORS, który działa w IE, Firefox, Chrome i Safari

 0
Author: Per Kristian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-27 08:26:25