【问题标题】:Tornado RESTful PUT handler method not getting request argumentsTornado RESTful PUT 处理程序方法未获取请求参数
【发布时间】:2012-08-14 22:05:02
【问题描述】:

我正在尝试对我的 RESTful API 进行单元测试。这是我的 API:


class BaseHandler(tornado.web.RequestHandler):                    
    def __init__(self, *args, **kwargs):                          
        tornado.web.RequestHandler.__init__(self, *args, **kwargs)
        self.log = self.application.log                           
        self.db = self.application.db                             

class ProductHandler(BaseHandler):
    @tornado.web.removeslash
    def put(self, id = None, *args, **kwargs):
        try:
            self.log.info("Handling PUT request")                                                             
            if not id:                                                                                                      
                raise Exception('Object Id Required')                                                                        
            id = { '_id' : id }                                                                                                                            
            new_values = dict()                                                                                             
            name = self.get_argument('name', None)                                                                          
            description = self.get_argument('description', None)                                                            
            if name:                                                                                                        
                new_values['name'] = name                                                                                   
            if description:                                                                                                 
                new_values['description'] = description                                                                     
            self.db.products.update(id, new_values, safe = True)                                                                                                               
        except:
            self.log.error("".join(tb.format_exception(*sys.exc_info())))                                                   
            raise                                                                                                           

 class Application(tornado.web.Application):                         
     def __init__(self, config_path, test = False, *args, **kwargs): 
         handlers = [                                                
             (r"/product/?(.*)", ProductHandler),                    
         ]                                                           
         settings = dict(debug=True)                                 
         tornado.web.Application.__init__(self, handlers, **settings)
         self.log = logging.getLogger(__name__)                      
         self.config = ConfigParser()                                
         self.config.read(config_path)                               
         self.mongo_connection = Connection(                         
             host = self.config.get('mongo','host'),                 
             port = self.config.getint('mongo','port'),              
         )                                                           
         if test:                                                    
             db_name = self.config.get('test', 'mongo.db')           
         else:                                                       
             db_name = self.config.get('mongo', 'db')                
         self.log.debug("Using db:  %s" % db_name)                   
         self.db = self.mongo_connection[db_name]                    

但是,这是我的问题:处理程序没有看到名称或描述参数。 :(

有什么建议吗?

【问题讨论】:

  • 我也注意到了。我最终将我的参数放在查询字符串上。我怀疑这与 asynchttpclient 没有“放置”写请求有关。

标签: python rest tornado


【解决方案1】:

作为一种解决方法,我在 request.body 中找到了它们并手动解析了编码参数。这有点烦人,但它确实有效。


new_values = urlparse.parse_qs(self.request.body)

# values show as lists with only one item
for k in new_values:                             
    new_values[k] = new_values[k][0]             

【讨论】:

  • 在不解释为什么没用的情况下拒绝投票。
【解决方案2】:

如果你使用 jQuery 来发送这个 PUT 请求:

$.ajax({
    type: "PUT",
    url: "/yourURL",
    data: JSON.stringify({'json':'your json here'),
    dataType: 'json'
})

data 不应该是这样的: data: {'json': 'your json here'}, 因为它会自动编码成查询字符串,需要通过parse_qs解析

然后在龙卷风中

def put(self, pid):
    d = json.loads(self.request.body)
    print d

【讨论】:

    【解决方案3】:

    如果请求具有正确的内容类型标头(application/x-www-form-urlencoded),put handler 将解析 request.body,例如,如果您使用的是 tornado http 客户端:

    headers = HTTPHeaders({'content-type': 'application/x-www-form-urlencoded'})
    http_client.fetch(
          HTTPRequest(url, 'PUT', body=urllib.urlencode(body), headers=headers))
    

    【讨论】:

      【解决方案4】:

      您是否尝试过改用get 方法?因为根据您测试程序的方式,如果您通过 Firefox 或 Chrome 等浏览器进行测试,他们可能能够做到。 Doing a HTTP PUT from a browser

      如果我是你,我会写 get 而不是 put。因为那你肯定可以在浏览器中测试它。

      例如,而不是:

      def put ...
      

      试试:

      def get ...
      

      或者实际上在你的:

      name = self.get_argument('name', None)                                                                          
      description = self.get_argument('description', None) 
      

      为什么None 在那里?根据documentation

      RequestHandler.get_argument(name, default=[], strip=True)

      ...

      如果未提供默认值,则认为该参数是必需的, 如果丢失,我们会抛出 HTTP 400 异常。

      因此,在您的情况下,因为您没有提供适当的默认值,因此您的应用返回 HTTP 400。错过了默认值! (即)

      name = self.get_argument('name')                                                                          
      description = self.get_argument('description') 
      

      【讨论】:

      • 我是故意使用 put 的。据我了解,这就是龙卷风的工作原理。而且,我正在使用 get_argument(arg, None) 因为我给调用者一个选项来更新产品上的一个或两个字段。
      • 你也可以使用get!这也是龙卷风的工作原理。 groups.google.com/forum/?fromgroups#!topic/python-tornado/…,你是如何测试你的程序的?
      • “我正在给调用者一个选项来更新产品上的一个或两个字段” - 您可以获取参数并测试参数是否为 None 如果 None 不更新特定领域。例如。 if name is None: ... Don't update name
      • 我正在使用tornado.testing.AsyncHTTPTestCase 进行单元测试。
      • 想知道您是否可以发布您的测试代码?你的测试代码有效吗?
      猜你喜欢
      • 2011-12-31
      • 2018-04-26
      • 2013-09-06
      • 1970-01-01
      • 1970-01-01
      • 2011-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多