我正在 Bottle Web 框架上开发 Web 服务的 RESTful API,并希望通过 jQuery AJAX 调用访问资源。
使用 REST 客户端,资源接口(interface)按预期工作并正确处理 GET、POST...请求。但是,当发送 jQuery AJAX POST 请求时,生成的 OPTIONS 预检请求会被简单地拒绝为“405:方法不允许”。
我尝试在 Bottle 服务器上启用 CORS - 如下所述:http://bottlepy.org/docs/dev/recipes.html#using-the-hooks-plugin 但是 OPTIONS 请求永远不会调用 after_request Hook 。
这是我的服务器的摘录:
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 预检请求呢?
最佳答案
安装处理程序而不是 Hook 。
我过去有两种互补的方法来完成此操作:装饰器或 Bottle 插件。我将向您展示两者,您可以决定其中之一(或两者)是否适合您的需求。在这两种情况下,总体思路是:处理程序在将响应发送回客户端之前拦截响应,插入 CORS header ,然后继续返回响应。
方法一:安装每路由(装饰器)
当您只想在某些路由上运行处理程序时,此方法更合适。只需装饰您希望其执行的每条路线即可。这是一个例子:
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插件)
如果您希望处理程序在所有或大部分路由上执行,那么此方法是更好的选择。你只需define a Bottle plugin一次,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)
关于jquery - Bottle Py : Enabling CORS for jQuery AJAX requests,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17262170/