【问题标题】:Can not post data via ajax to web2py rest api - possible CORS issue无法通过 ajax 将数据发布到 web2py rest api - 可能的 CORS 问题
【发布时间】:2016-10-14 21:04:53
【问题描述】:

我已经搜索这个问题的答案将近两周了。我有一个内置 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");
    }
});

数据库表没有更新,但请求运行成功。它每次都返回一个空对象。{}

【问题讨论】:

    标签: javascript python ajax cors web2py


    【解决方案1】:

    好的,我通过做三件事解决了这个问题。 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";
    
    1. 我修改了 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

    【讨论】:

      【解决方案2】:

      您的wrapper 函数调用return dict(),它在调用f() 之前执行,因此装饰的api 函数永远不会被调用。只需删除该行。

      另外,请注意,根据 Ajax 请求的性质,浏览器可能首先发出preflight request。因此,您的装饰器代码将需要使用appropriate headers 检测和响应此类请求。

      【讨论】:

      • 嘿,安东尼,非常感谢。我注释掉了 return dict() 代码行,现在我收到以下错误... XMLHttpRequest 无法加载127.0.0.1:8000/cc/default/api/myboard.json。预检响应无效(重定向)
      • 另外两点:1.在注释掉以下装饰器@auth.requires_login() 和@request.restful() 以及将response.view 更改为'generic.'+request.extension ajax 请求运行成功(代码 200)但数据未插入数据库:2 并且返回消息是来自 api 页面的 html 脚本。很奇怪
      • 我更新了答案。另外,请注意,您不能删除 @request.restful 装饰器,因为 web2py 需要它来将对 api() 的调用转换为对嵌入式 POST() 函数的调用。
      • 谢谢安东尼。这完全有道理。因此,在取消注释 @request.restful 装饰器后,我收到以下“预检”消息:“对预检请求的响应未通过访问控制检查:请求的资源上不存在 'Access-Control-Allow-Origin' 标头。来源'localhost:63342' 因此不允许访问。响应的 HTTP 状态代码为 405。”就好像 CORS 装饰器现在根本不存在。
      • 我还收到一条 405 METHOD NOT ALLOWED 消息。网络显示的方法是 OPTIONS
      猜你喜欢
      • 1970-01-01
      • 2015-02-20
      • 1970-01-01
      • 2016-08-19
      • 2016-11-06
      • 1970-01-01
      • 2021-04-07
      • 2014-01-25
      • 2016-10-08
      相关资源
      最近更新 更多