小编典典

Bottle Py:为jQuery AJAX请求启用CORS

ajax

我正在使用Bottle Web Framework上的Web服务的RESTful API,并希望通过jQuery AJAX调用来访问资源。

使用REST客户端,资源接口可按预期工作并正确处理GET,POST,…请求。但是,当发送jQuery AJAX
POST请求时,最终的OPTIONS预检请求被简单地拒绝为“ 405:不允许使用方法”。

我试图在Bottle服务器上启用 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飞行前请求?


阅读 379

收藏
2020-07-26

共1个答案

小编典典

安装一个处理程序而不是一个钩子。

我过去有两种互补的方法:装饰器或Bottle插件。我将向您展示两者,您可以决定它们中的一个(或两者)是否满足您的需求。在这两种情况下,通常的想法是:处理程序在将响应发送回客户端之前先对其进行拦截,然后插入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:全局安装(瓶插件)

如果希望处理程序在所有或大多数路由上执行,则最好使用此方法。您只需定义一次Bottle插件,Bottle就会在每条路线上自动为您调用它;无需在每一个上指定一个装饰器。(请注意,您可以使用路由的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)
2020-07-26