2014-10-01 155 views
4

我使用Python 2.7.5,Django的1.7,要求2.4.1,并做一些简单的测试。但是,它看起来像我调用requests.post时,该方法是做一个GET。Python请求POST做GET?

我的代码,跟一个REST的API。请注意,POST指令通过Hurl.it可与该有效载荷和终点:

def add_dummy_objective(self): 
    """ 
    To the bank 
    """ 
    payload = { 
     'displayName': { 
      'text': self._test_objective 
     }, 
     'description': { 
      'text': 'For testing of API Middleman' 
     }, 
     'genusTypeId': 'DEFAULT' 
    } 
    obj_url = self.host + self.bank_id + '/objectives/?proxyname=' + self._admin_key 
    req = requests.post(obj_url, data=json.dumps(payload), headers=self.headers) 
    return req.json() 

我设置了标题为JSON:

self.headers = { 
    'Content-Type' : 'application/json' 
} 

而不是创建一个新的目标(如用POST预期),我得到了一个目标列表(我期望得到一个GET)。使用pdb,我看到:

(Pdb) req.request 
<PreparedRequest [GET]> 
(Pdb) req.request.method 
'GET' 

这是如何翻转的?我已经使用了Python没有问题之前请求库,所以我不知道如果我失去了一些东西明显,或者(和Django /采购的新版本),我必须设置其他参数?这是一个缓存问题吗?任何调试技巧?我尝试重新安装请求,并将Django回滚到1.6.5,但没有任何工作......一定很简单。 - 谢谢!

======更新1个========

只是巩固了一些调试信息的那马亭这里建议:

(Pdb) requests.post.__name__ 
'post' 

步入请求/ API。 PY>柱()定义:

(Pdb) l 
88   :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`. 
89   :param \*\*kwargs: Optional arguments that ``request`` takes. 
90   """ 
91   import pdb 
92   pdb.set_trace() 
93 ->  return request('post', url, data=data, **kwargs) 

钻孔向下进入请求()方法:

(Pdb) method 
'post' 
(Pdb) l 
43   >>> req = requests.request('GET', 'http://httpbin.org/get') 
44   <Response [200]> 
45   """ 
46   import pdb 
47   pdb.set_trace() 
48 ->  session = sessions.Session() 
49   return session.request(method=method, url=url, **kwargs) 

还有一层,在session.request:

(424)request() 
-> method = builtin_str(method) 
(Pdb) method 
'post' 
(Pdb) l 
419    :param cert: (optional) if String, path to ssl client cert file (.pem). 
420     If Tuple, ('cert', 'key') pair. 
421    """ 
422    import pdb 
423    pdb.set_trace() 
424 ->   method = builtin_str(method) 
425 
426    # Create the Request. 
427    req = Request(
428     method = method.upper(), 
429     url = url, 

下台该方法,其中该请求实际上是由结束时,我的“制备”是一个POST,但我的RESP是GET:

(Pdb) prep 
<PreparedRequest [POST]> 
(Pdb) n 
-> return resp 
(Pdb) resp 
<Response [200]> 
(Pdb) resp.request 
<PreparedRequest [GET]> 
(Pdb) l 
449     'allow_redirects': allow_redirects, 
450    } 
451    send_kwargs.update(settings) 
452    resp = self.send(prep, **send_kwargs) 
453 
454 ->   return resp 
455 
456   def get(self, url, **kwargs): 
457    """Sends a GET request. Returns :class:`Response` object. 
458 
459    :param url: URL for the new :class:`Request` object. 
+0

您发布的代码将不*生成GET,它将生成POST。你是否100%确定你正在执行正确的代码路径? – 2014-10-01 19:42:04

+0

这是我的单元测试的一部分,我正在逐行执行,所以我99%肯定这是它遵循的代码路径 - 如果有其他方法检查以消除1%,我是不知道如何,但会很乐意去做... – user 2014-10-01 19:46:32

+0

顺便说一下,我同意并理解上面的代码应该产生一个POST ...所以我认为别的是错的(1%)。如果我使用错误的代码路径,还有什么其他方法可以找到我正在执行的路径(除了pdb)? – user 2014-10-01 19:48:40

回答

9

需要明确的是,每当收到的请求重定向(有一定的status code),我们必须对请求执行某些转换。

在这样的情况下,当你看到一些很意外的最好的调试技巧是重试您的请求,但与allow_redirects=False。这将立即返回30倍响应。另外,您还可以检查r.history,看看是否有随访任何30X响应。在这种情况下,你可能会看到类似

>>> r.request.method 
'GET' 
>>> r.history 
[<Response [302]>,] 
>>> r.history[0].request.method 
'POST' 

我们知道,这样做可能会导致使用者意外的行为(因为它只是做给你),但它在网络上操作的唯一正确途径。

我希望这可以帮助你理解为什么发生超出了事实,这是一个重定向,并希望它可以让你和其他工具,以在未来的调试此。

+0

感谢您的明确解释!找到这个之后,我做了一些关于重定向的阅读,并且更好地理解了为什么图书馆的行为如此... – user 2014-10-02 14:54:55

6

感谢Martijn提供了一些调试技巧!这个问题是REST风格的API被重定向我从http://到https://,这引起了库返回“第二”请求(GET)...