Подтвердить что ты не робот

Задача межсетевого пространства Flask RESTful с помощью методов Angular: PUT, OPTIONS

Я разработал небольшой REST api для записи только с Flask Restful, который принимает запрос PUT от нескольких клиентов, которые потенциально могут изменять IP-адреса. Мои клиенты - это встроенные клиенты Chromium, работающие с интерфейсом AngularJS; они аутентифицируются с помощью моего API с помощью простого волшебного ключа - этого достаточно для моего очень ограниченного масштаба.

Я тестирую развертывание своего API сейчас, и я замечаю, что клиенты Angular пытаются отправить методы OPTIONS http в мою службу Flask. Мой API тем временем отвечает 404 (поскольку я еще не писал обработчик OPTIONS, только обработчик PUT). Похоже, что при отправке междоменных запросов, которые не являются POST или GET, Angular отправит на сервер метод перед полетом OPTIONS, чтобы убедиться, что запрос по междоменному запросу принят до отправки фактического запроса. Правильно ли это?

В любом случае, как мне разрешить все междоменные запросы PUT для Flask Restful API? Я использовал кросс-domaion decorators с (non-restful) экземпляром Flask раньше, но мне также нужно написать обработчик OPTIONS также в мой API?

4b9b3361

Ответ 1

Я решил проблему, переписав мою флэшку, чтобы ответить с заголовком Access-Control-Allow-Origin в ответе PUT. Кроме того, я создал обработчик OPTIONS в моем приложении Flask, чтобы ответить на метод опций, следуя тому, что я прочитал в http RFC.

Возврат метода PUT выглядит следующим образом:

return restful.request.form, 201, {'Access-Control-Allow-Origin': '*'} 

Обработчик метода My OPTIONS выглядит так:

def options (self):
    return {'Allow' : 'PUT' }, 200, \
    { 'Access-Control-Allow-Origin': '*', \
      'Access-Control-Allow-Methods' : 'PUT,GET' }

@tbicr является правильным: Флажок ДОЛЖЕН автоматически отвечать на метод OPTIONS. Однако в моем случае он не передавал заголовок Access-Control-Allow-Origin с этим ответом, поэтому мой браузер получал ответ от api, который, казалось, подразумевал, что междоменные запросы не разрешены. Я перегрузил запрос параметров в моем случае и добавил заголовок ACAO, и браузер, похоже, был доволен этим, и следил за OPTIONS с помощью PUT, который также работал.

Ответ 2

С помощью модуля Flask-CORS вы можете выполнять междоменные запросы без изменения вашего кода.

from flask.ext.cors import CORS

app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})

Обновить

Как предложил Эрик, модуль flask.ext.cors устарел, лучше использовать следующий код:

from flask_cors import CORS

app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})

Ответ 3

Вы можете использовать крюк after_request:

@app.after_request
def after_request(response):
    response.headers.add('Access-Control-Allow-Origin', '*')
    response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
    response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
    return response

Подробнее об этом руководстве см. http://tutsbucket.com/tutorials/building-a-blog-using-flask-and-angularjs-part-1/

Ответ 4

Вы правы, метод OPTIONS вызывается каждый раз перед реальным запросом в браузере. OPTIONS ответ разрешил методы и заголовки. Flask автоматически обрабатывает запросы OPTIONS.

Чтобы получить доступ к запросу междоменного домена, API должен иметь заголовок Access-Control-Allow-Origin. Он может содержать определенные домены, но если вы хотите разрешить запросы из любых доменов, вы можете установить его на Access-Control-Allow-Origin: *.

Чтобы настроить CORS для flask, вы можете посмотреть один код расширения или попробовать использовать это расширение: https://github.com/wcdolphin/flask-cors/blob/master/flask_cors.py.

Чтобы настроить CORS для flask-restful, смотрите эти запросы: https://github.com/twilio/flask-restful/pull/122 и https://github.com/twilio/flask-restful/pull/131. Но похоже, что flask-restful по умолчанию не поддерживает его.

Ответ 5

Просто обновите этот комментарий. Флакон CORS - это путь, но flask.ext.cors устарел.

использование: from flask_cors import CORS

Ответ 6

Как об этом обходном пути:

from flask import Flask
from flask.ext import restful
from flask.ext.restful import Api
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config.from_object('config')

#flask-sqlalchemy
db = SQLAlchemy(app)

#flask-restful
api = restful.Api(app)

@app.after_request

def after_request(response):
  response.headers.add('Access-Control-Allow-Origin', '*')
  response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
  response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
  return response

import views

Я взял это из этого учебника. Работает очень хорошо. на самом деле, я думаю, что это лучший подход, который я видел до сих пор.

Возврат {'Access-Control-Allow-Origin': '*'} на каждой конечной точке, кажется, не эффективен, так как вы должны добавить его на каждую конечную точку. немного анонимный..., по крайней мере для меня.

Я попробовал @cors.crossdomain(origin='*'), но, похоже, он работает только с запросом GET.

Ответ 7

Мне нравится использовать украшение для решения.

def cross_origin(origin="*"):
    def cross_origin(func):
        @functools.wraps(func)
        def _decoration(*args, **kwargs):
            ret = func(*args, **kwargs)
            _cross_origin_header = {"Access-Control-Allow-Origin": origin,
                                    "Access-Control-Allow-Headers":
                                        "Origin, X-Requested-With, Content-Type, Accept"}
            if isinstance(ret, tuple):
                if len(ret) == 2 and isinstance(ret[0], dict) and isinstance(ret[1], int):
                    # this is for handle response like: ```{'status': 1, "data":"ok"}, 200```
                    return ret[0], ret[1], _cross_origin_header
                elif isinstance(ret, basestring):
                    response = make_response(ret)
                    response.headers["Access-Control-Allow-Origin"] = origin
                    response.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
                    return response
                elif isinstance(ret, Response):
                    ret.headers["Access-Control-Allow-Origin"] = origin
                    ret.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
                    return ret
                else:
                    raise ValueError("Cannot handle cross origin, because the return value is not matched!")
            return ret

        return _decoration

    return cross_origin

И затем, используйте украшение в вашем спокойном api.

class ExampleRestfulApi(Resource)
    @cross_origin()
    def get(self):
        # allow all cross domain access
        pass

    @cross_origin(origin="192.168.1.100")
    def post(self):
        # allow 192.168.1.100 access
        pass

Ответ 8

Чтобы разрешить удаленные запросы CORS на API вашего веб-сервиса, вы можете просто инициализировать API-интерфейс колбы, как это:

from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
from flask_cors import CORS

app = Flask(__name__)
cors = CORS(app, resources={r"*": {"origins": "*"}})
api = Api(app)

Это добавляет заголовок CORS к вашему экземпляру API и разрешает запрос CORS по каждому пути из каждого источника.