Бутылка Py: включение CORS для запросов jQuery AJAX

Я работаю над RESTful API веб-службы на веб-фреймворке бутылки и хочу получить доступ к ресурсам с помощью вызовов jQuery AJAX.

используя клиент REST, интерфейсы ресурсов работают по назначению и правильно обрабатывают GET, POST, ... запросы. Но при отправке запроса jQuery AJAX POST результирующий запрос параметров preflight просто отклоняется как "405: метод не разрешен".

Я попытался включить CORS на сервере бутылки - как описано здесь: http://bottlepy.org/docs/dev/recipes.html#using-the-hooks-plugin Но ... --10-->after_request крючком никогда не вызывается для запроса параметров.

вот выдержка из моего сервера:

from bottle import Bottle, run, request, response
import simplejson as json

app = Bottle()

@app.hook('after_request')
def enable_cors():
    print "after_request hook"
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
    response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'

@app.post('/cors')
def lvambience():
    response.headers['Content-Type'] = 'application/json'
    return "[1]"

[...]

вызов jQuery AJAX:

$.ajax({
    type: "POST",
    url: "http://192.168.169.9:8080/cors",
    data: JSON.stringify( data ),
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function(data){
        alert(data);
    },
    failure: function(err) {
        alert(err);
    }
});

сервер регистрирует только ошибку 405:

192.168.169.3 - - [23/Jun/2013 17:10:53] "OPTIONS /cors HTTP/1.1" 405 741

$.post работает,но неспособность отправлять запросы PUT победит цель службы RESTful. Итак, как я могу разрешить варианты запрос на предполетную обработку?

4 ответов


установите обработчик вместо крючка.

есть два дополнительных способа, которые я сделал это в прошлом: декоратор или плагин для бутылок. Я покажу вам оба, и вы можете решить, подходит ли один (или оба) из них вашим потребностям. В обоих случаях общая идея: обработчик перехватывает ответ до его отправки обратно клиенту, вставляет заголовки CORS, а затем переходит к возвращению ответа.

метод 1: Установка по маршруту (декоратор)

этот метод предпочтительнее, когда вы хотите запустить обработчик только на некоторых маршрутах. Просто украсьте каждый маршрут, который вы хотите его выполнить. Вот пример:

import bottle
from bottle import response

# the decorator
def enable_cors(fn):
    def _enable_cors(*args, **kwargs):
        # set CORS headers
        response.headers['Access-Control-Allow-Origin'] = '*'
        response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
        response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'

        if bottle.request.method != 'OPTIONS':
            # actual request; reply with the actual response
            return fn(*args, **kwargs)

    return _enable_cors


app = bottle.app()

@app.route('/cors', method=['OPTIONS', 'GET'])
@enable_cors
def lvambience():
    response.headers['Content-type'] = 'application/json'
    return '[1]'

app.run(port=8001)

Метод 2: Установите Глобально (Плагин Бутылки)

этот метод предпочтительнее, если вы хотите, чтобы обработчик выполнялся на всех или большинстве ваших маршрутов. Ты просто ... --14-->определите плагин бутылки раз, и бутылка автоматически вызовет ее для вас на каждом маршруте; отсутствие потребности определить декоратора дальше каждый. (Обратите внимание, что вы можете использовать маршруте


вот небольшое улучшение на @ron.метод Ротмана #2 для установки обработчика CORS глобально. Его метод требует, чтобы вы указали, что OPTIONS метод принимается на каждом объявленном вами маршруте. Это решение устанавливает глобальный обработчик для всех OPTIONS запросы.

@bottle.route('/<:re:.*>', method='OPTIONS')
def enable_cors_generic_route():
    """
    This route takes priority over all others. So any request with an OPTIONS
    method will be handled by this function.

    See: https://github.com/bottlepy/bottle/issues/402

    NOTE: This means we won't 404 any invalid path that is an OPTIONS request.
    """
    add_cors_headers()

@bottle.hook('after_request')
def enable_cors_after_request_hook():
    """
    This executes after every route. We use it to attach CORS headers when
    applicable.
    """
    add_cors_headers()

def add_cors_headers():
    if SOME_CONDITION:  # You don't have to gate this
        bottle.response.headers['Access-Control-Allow-Origin'] = '*'
        bottle.response.headers['Access-Control-Allow-Methods'] = \
            'GET, POST, PUT, OPTIONS'
        bottle.response.headers['Access-Control-Allow-Headers'] = \
            'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'

``


подумайте о том, чтобы ваш веб-сервер, а не бутылка, установил заголовки.

Не уверен, применимо ли это в вашей ситуации, но я решил проблему в прошлых проектах, установив заголовки CORS для моего приложения бутылки в Apache. Это легко настроить, сохраняет мой код Python красивым и чистым и эффективным.

информация из многих источников, но если вы используете Apache, вот как выглядит моя конфигурация (более или менее):

<Location "/cors">
    Header set Access-Control-Allow-Headers "Origin, Content-Type"
    Header set Access-Control-Allow-Methods "POST, GET, OPTIONS"
    Header set Access-Control-Allow-Origin "*"
    Header set Access-Control-Request-Headers "Origin, Content-Type"
</Location>

также не должны ли вы на самом деле использовать это?

response.set_header('Access-Control-Allow-Origin', '*')
response.add_header('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS')