2016-06-14 71 views
1

我已经搜索了近两周的问题的答案。我有一个简单的系统内置web2py。注意:我不完全是一位蟒蛇老手。我正在尝试使用web2py rest api将数据发布到数据库。如果我运行curl命令,数据库表会更新,其余的将返回新添加的行的ID。这是理想的结果。但是,如果我尝试使用ajax请求来执行相同的操作,则请求运行成功,但其他请求会返回空对象,并且数据库不会更新。我已经添加了一个CORS包装类,它允许我通过跨源问题;但我不确定这是否同时阻止了数据库的更新等。我被踩踏了。另外请注意,我将数据格式化为ajax对象,但仍然没有任何结果。请找到下面的所有代码。无法通过ajax发布数据到web2py rest api - 可能的CORS问题

最重要的:我收到以下消息 - 响应预检请求未通过访问控制检查:否“访问控制允许来源”标题存在于所请求的资源。

任何/所有的帮助是非常感谢球员。谢谢:)

#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 [email protected]: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 = ’[email protected]'; 
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

wrapper函数调用return dict(),它调用f()之前执行的,所以装饰api功能不会被调用。只要删除该行。

此外,请注意,根据Ajax请求的性质,浏览器可能首先制作一个preflight request。所以,你的装饰器代码将需要检测并回应这样的请求与appropriate headers

+0

嘿安东尼,谢谢一堆。我注释掉了返回字典()的代码行,现在我收到以下错误... XMLHttpRequest无法加载http://127.0.0.1:8000/cc/default/api/myboard.json。预检反应无效(重定向) –

+0

另外两点:1.在注释掉以下装饰器@ auth.requires_login()AND @ request.restful()以及将response.view更改为'generic。'+ request。扩展ajax请求成功运行(代码200),但数据未插入到数据库中:2并且返回消息是来自api页面的html脚本。很奇怪 –

+0

我更新了答案。另外,请注意,您不能删除'@ request.restful'装饰器,因为它是为了让web2py将调用转换为'api()'为调用嵌入式'POST()'函数所必需的。 – Anthony

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