web-dev-qa-db-ja.com

Bottle Py:jQueryのCORSを有効にするAJAXリクエスト

Bottle Web Framework上のWebサービスのRESTful APIに取り組んでいて、jQuery AJAX呼び出しでリソースにアクセスしたい。

RESTクライアントを使用すると、リソースインターフェースは意図したとおりに機能し、GET、POSTなどのリクエストを適切に処理します。ただし、jQueryを送信するときAJAX POSTリクエスト、結果のOPTIONSプリフライトリクエストは、「405:Method not allowed」として拒否されます。

私はボトルサーバーでCORSを有効にしようとしました-ここで説明されているように http://bottlepy.org/docs/dev/recipes.html#using-the-hooks-plugin しかしafter_requestフックがOPTIONS要求に対して呼び出されることはありません。

これが私のサーバーの抜粋です:

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サービスの目的が損なわれます。では、OPTIONSプリフライトリクエストの処理を許可するにはどうすればよいですか?

22
Joern

フックの代わりにハンドラーをインストールします。

これまで私がこれを行った補完的な方法が2つあります。それは、デコレーターとボトルプラグインです。両方を表示し、どちらか(または両方)がニーズに合っているかどうかを判断できます。どちらの場合も、一般的な考え方は次のとおりです。ハンドラーは、クライアントに返送される前に応答をインターセプトし、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:グローバルにインストール(ボトルプラグイン)

この方法は、すべてまたはほとんどのルートでハンドラーを実行する場合に適しています。 ボトルプラグインを定義する を1回入力するだけで、すべてのルートでボトルが自動的に呼び出します。それぞれにデコレータを指定する必要はありません。 (ルートのskipパラメーターを使用して、ルートごとにこのハンドラーを回避できることに注意してください。)上記に対応する例を次に示します。

import bottle
from bottle import response

class EnableCors(object):
    name = 'enable_cors'
    api = 2

    def apply(self, fn, context):
        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'])
def lvambience():
    response.headers['Content-type'] = 'application/json'
    return '[1]'

app.install(EnableCors())

app.run(port=8001)
32
ron rothman

CORSハンドラーをグローバルにインストールするための@ ron.rothmanのメソッド#2のマイナーな改善点を以下に示します。彼のメソッドでは、宣言するすべてのルートで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'

「」

6
BrainCore

また、実際にこれを使用してはいけませんか?

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

ボトルではなくウェブサーバーにヘッダーを設定させることを検討してください。

これがあなたの状況に当てはまるかどうかはわかりませんが、私は過去のプロジェクトの問題をApacheのボトルアプリケーションにCORSヘッダーを設定することで解決しました。設定は簡単で、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>
1
ron rothman