近两周我一直在寻找这个问题的答案。我有一个内置web2py的简单系统。注意:我不是一个蟒蛇老兵。我试图使用web2py rest api将数据发布到数据库。如果我运行curl命令,则更新数据库表,其余的返回新添加的行的id。这是期望的结果。但是,如果我尝试使用ajax请求执行相同的操作,请求会成功运行,但其余的返回一个空对象,并且数据库不会更新。我添加了一个CORS包装器类,它允许我克服跨源问题;但我不确定这是否同时阻止数据库更新等等。我被踩了。另请注意,我将数据(在ajax调用中)格式化为json对象,但仍然没有。请在下面找到所有代码。
最重要的是:我收到以下消息 - 对预检请求的响应未通过访问控制检查:请求的资源上没有“Access-Control-Allow-Origin”标头。
任何/所有帮助都非常感谢大家。谢谢:))
#Web2py model
db.define_table(‘myboard',
#Field('userid','reference auth_user'),
Field('userid',db.auth_user,default=auth.user_id),
Field('title',requires=IS_LENGTH(100,1),label=“Board Title"),
Field(‘idea_a',requires=IS_LENGTH(75,1),label=“Idea A"),
Field(‘idea_b',requires=IS_LENGTH(75,1),label=“Idea B"),
Field('description','text',requires=IS_LENGTH(250,1),label=“Board Description"),
Field('contributors','integer',default='0'),
Field('status','integer',writable=False,readable=False,default='1'), #1=draft, 2=public
Field('created_on','datetime',writable=False,default=request.now))
#Web2py controllers
def CORS(f):
"""
Enables CORS for any action
"""
def wrapper(*args, **kwargs): #*args, **kwargs
if request.env.http_origin:
response.headers['Access-Control-Allow-Origin'] = request.env.http_origin
response.headers['Access-Control-Allow-Credentials'] = "true";
response.headers['Access-Control-Allow-Headers'] = "Authorization,Content-Type,data";
return dict()
return f(*args, **kwargs)
return wrapper
auth.settings.allow_basic_login = True
@CORS
@request.restful()
def api():
from gluon.serializers import json
response.view = 'generic.'+request.extension
def GET(*args,**vars):
patterns = 'auto'
parser = db.parse_as_rest(patterns,args,vars)
if parser.status == 200:
return dict(content=parser.response)
else:
raise HTTP(parser.status,parser.error)
def POST(table_name,**vars):
return json(db[table_name].validate_and_insert(**vars))
return dict()
def PUT(table_name,record_id,**vars):
return db(db[table_name]._id==record_id).update(**vars)
def DELETE(table_name,record_id):
return db(db[table_name]._id==record_id).delete()
return dict(GET=GET, PUT=PUT, POST=POST, DELETE=DELETE)
//CURL COMMAND - This Works!
curl -i --user somename@gmail.com:thepassword -H Accept:application/json -X POST http://127.0.0.1:8000/cc/default/api/myboard.json -H Content-Type: application/json -d 'userid=2&title=THE_TITLE&description=THE_DESCRIP&idea_a=THE 1st idea&idea_b=THE 2nd idea’
//AJAX CALL - Doesn't Work :(
var userid = 2;
var title = "THE_TITLE_HERE";
var description = "THE_DESCRIPTION_HERE"
var idea_a = "THE 1st idea";
var idea_b = "THE 2nd idea";
var userID = ’somename@gmail.com';
var password = ’thepassword';
var theData = "userid=2&title="+title+"&description="+description+”&idea_a=“+ideaA+”&idea_b=“+ideaB;
$.ajax({
type: 'POST',
headers: {"Authorization": "Basic " + btoa(userID + ":" + password)},
url: "http://127.0.0.1:8000/cc/default/api/myboard.json",
contentType: "application/json; charset=utf-8",
data: theData,
success: function (data,textStatus,jqXHR) {
alert(textStatus);
console.log(data);
},
error: function(){
alert("Cannot get data");
}
});
数据库表未更新,但请求成功运行。它每次返回一个空对象.. {}
答案 0 :(得分:0)
您的wrapper
函数调用return dict()
,它在调用f()
之前执行,因此永远不会调用已修饰的api
函数。只需删除该行。
另请注意,根据Ajax请求的性质,浏览器可能首先生成preflight request。因此,您的装饰器代码需要使用appropriate headers检测并响应此类请求。
答案 1 :(得分:0)
好的,我做了三件事就解决了这个问题。 1.我从控制器文件中删除了CORS装饰器代码 - default.py 2.我将以下代码插入default.py控制器文件
的顶部if request.env.http_origin:
response.headers['Access-Control-Allow-Origin'] = request.env.http_origin;
response.headers['Access-Control-Allow-Methods'] = "POST,GET,OPTIONS";
response.headers['Access-Control-Allow-Credentials'] = "true";
response.headers['Access-Control-Allow-Headers'] = "Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Accept-Encoding";
我修改了api类以包含OPTIONS动词,方法是在DELETE动词之后在类的底部添加以下内容。修改后的api类如下.. 注意:更改位于最后4行代码中。
def api():
from gluon.serializers import json
response.view = 'generic.'+request.extension
def GET(*args,**vars):
patterns = 'auto'
parser = db.parse_as_rest(patterns,args,vars)
if parser.status == 200:
return dict(content=parser.response)
else:
raise HTTP(parser.status,parser.error)
def POST(table_name,**vars):
#return db[table_name].validate_and_insert(**vars)
#data = gluon.contrib.simplejson.loads(request.body.read())
return json(db[table_name].validate_and_insert(**vars))
return dict()
def PUT(table_name,record_id,**vars):
return db(db[table_name]._id==record_id).update(**vars)
def DELETE(table_name,record_id):
return db(db[table_name]._id==record_id).delete()
def OPTIONS(*args,**vars):
print "OPTION called"
return True
return dict(GET=GET,POST=POST,PUT=PUT,DELETE=DELETE,OPTIONS=OPTIONS)
就是这样。问题在于web2py,因为我需要在api调用中包含OPTIONS动词并且直接在控制器文件的顶部包含头文件的代码,而不是将它放在包装器中似乎对我有用。现在一切都连接起来,数据库也会更新。
参考网址:https://github.com/OpenTreeOfLife/phylesystem-api/issues/26