Вирішіть спільне використання джерел ресурсів за допомогою колби


86

Для наступного ajaxзапиту на публікацію для Flask( як я можу використовувати дані, розміщені з ajax у колбі? ):

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

Я отримую повідомлення про Cross Origin Resource Sharing (CORS)помилку:

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.

Я спробував вирішити це двома наступними способами, але, здається, жоден не працює.

  1. Використання Flask-CORS

Це Flaskрозширення для обробки, CORSяке повинно зробити можливим AJAX з перехресним походженням.

Мій pythonServer.py за допомогою цього рішення:

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. Використання спеціального декоратора колб

Це офіційний фрагмент коду Flask, що визначає декоратор, який повинен дозволяти CORSфункції, які він прикрашає.

Мій pythonServer.py за допомогою цього рішення:

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

Чи можете ви, будь ласка, вказати, чому це так?


ти зрозумів? Я стикаюся з точно такою ж проблемою :(
shao

Це старе запитання, але щоб бути впевненим: Ви перезапустили свій сервер Flask? Я також дивувався, чому я отримав ту саму помилку, навіть думаючи, що все було саме так, як слід. Виявляється, вам доведеться перезапустити сервер, щоб він дійсно
набув

Відповіді:


53

Це працювало як чемпіон після бітової модифікації вашого коду

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

Я замінив * на localhost. Оскільки я читав у багатьох блогах та публікаціях, ви повинні дозволити доступ до певного домену


2
Якщо хтось використовує креслення, вам потрібно додати CORS () до кожного креслення, наприклад: my_blueprint = Blueprint ('my_bp_name', name , url_prefix = "/ my-prefix") CORS (my_blueprint)
BLang

90

Отримати результати можна за допомогою простого:

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

1
Краще, ніж додавання міждоменної реалізації!
Флореску Каталін

Просто та ефективно
Ентоні

4
Блискуче! Погоджуюсь, просто та ефективно. Відповідь ІМО повинна бути прийнята
ПАЛЕН

3
@Salvador Dali - Чи знаєте ви, як правильно дозволити перехресне походження, якщо я відображаю шаблон, а не просто об'єкт json? тобто останній рядок коду в yourMethod:return render_template('template.html',some_var = response)
Маттео

3
Чи можна це використовувати у методі публікації? Я спробував використати метод завантаження файлу, але мені не вдалося.
W.Leto

64

Ну, я зіткнувся з тим же питанням. Для нових користувачів, які можуть потрапити на цю сторінку. Просто дотримуйтесь їх офіційної документації.

Встановіть колбу-кор

pip install -U flask-cors

потім після ініціалізації програми ініціалізуйте flask-corsаргументами за замовчуванням:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

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

Це призводить до наступної помилки для мене. Доступ до XMLHttpRequest у 'my_domain' від джерела ' 127.0.0.1:5000 ' заблокований політикою CORS: Відповідь на попередній запит не проходить перевірку контролю доступу: 'Access-Control-Allow- Заголовок "Origin" містить кілька значень " 127.0.0.1:5000 , * ', але дозволено лише одне.
humblePilgrim

Не працює у мене. stackoverflow.com/questions/59652099/…
WP McNeill

Працює і для мене Tks!
Хосе

Працював у мене! Велике спасибі :)
XpressGeek

як встановити Access-Control-Max-Ageдля flask_cors?
DragonKnight

5

Можна також зробити це відповіддю. У мене було те саме питання сьогодні, і це було більше питання, ніж очікувалося. Після додавання функціональності CORS, ви повинні перезапустити ваш сервер Flask ( ctrl + c-> python manage.py runserverабо будь-який метод, який ви використовуєте)), щоб зміна набрала чинності, навіть якщо код правильний. В іншому випадку CORS не працюватиме в активному екземплярі.

Ось як це виглядає для мене і як це працює (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"
        })

У моєму додатку React console.log:

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

4

Зверніть увагу, що встановлення Access-Control-Allow-Originзаголовка в об’єкті відповіді Flask у багатьох випадках є нормальним (наприклад, у цьому), але це не впливає на обслуговування статичних активів (принаймні у виробничих налаштуваннях). Це тому, що статичні активи обслуговуються безпосередньо фронтальним веб-сервером (як правило, Nginx або Apache). Отже, у такому випадку вам слід встановити заголовок відповіді на рівні веб-сервера, а не в Flask.

Детальніше див. У цій статті, яку я написав деякий час тому, пояснюючи, як встановити заголовки (у моєму випадку я намагався зробити міждоменне обслуговування об’єктів Font Awesome).

Крім того, як сказав @Satu, можливо, вам доведеться дозволити доступ лише для певного домену, у випадку запитів JS AJAX. Щодо запиту статичних об’єктів (наприклад, шрифтових файлів), я вважаю, що правила є менш суворими, і більш прийнятним є доступ до будь-якого домену.


3

Я використовував декоратор, наданий Armin Ronacher, з невеликими змінами (через різні заголовки, які вимагає клієнт), і який працював у мене. (де я використовую angular як запитувач, що запитує тип програми / json).

Код трохи змінений внизу,

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 надішле тип програми / json, інакше це буде текст / html. заголовки додаються як клієнт у моєму запиті на ці заголовки

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

2
Посилання на декоратора мертве
Хосе Томас Точіно

2

Примітка: Розміщення cross_origin має бути правильним, а залежності встановлені. На стороні клієнта переконайтеся, що вказано тип сервера даних, який споживається. Наприклад application / json або text / html

Для мене код, написаний нижче, зробив магію

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)

чому ви робите те саме (support_credentials = True) у cross_origin?
Езіз Дурдієв

1

Можливо, я запізнився з цим питанням, але нижче описані кроки вирішили проблему

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

0

Я багато боровся з чимось подібним. Спробуйте наступне:

  1. Використовуйте якийсь плагін браузера, який може відображати заголовки HTML.
  2. Введіть URL-адресу вашої служби та перегляньте повернені значення заголовка.
  3. Переконайтеся, що Access-Control-Allow-Origin встановлено як один і лише один домен, який повинен бути джерелом запиту. Не встановлюйте для Access-Control-Allow-Origin значення *.

Якщо це не допомогло, погляньте на цю статтю. Це на PHP, але він точно описує, які заголовки мають бути встановлені, які значення для роботи CORS.

CORS, який працює в IE, Firefox, Chrome та Safari

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.