Python 请求 POST 执行 GET? [英] Python Requests POST doing a GET?

查看:28
本文介绍了Python 请求 POST 执行 GET?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Python 2.7.5、Django 1.7、请求 2.4.1,并进行一些简单的测试.但是,似乎当我调用 requests.post 时,该方法正在执行 GET.

我的代码,与 RESTful API 对话.请注意,POST 命令通过 Hurl.it 与此有效负载和端点一起工作:

def add_dummy_objective(self):"""去银行"""有效载荷 = {'显示名称': {'文本':self._test_objective},'描述': {'text': '用于测试 API 中间人'},'genusTypeId': '默认'}obj_url = self.host + self.bank_id + '/objectives/?proxyname=' + self._admin_keyreq = requests.post(obj_url, data=json.dumps(payload), headers=self.headers)返回 req.json()

我将标题设置为 json:

self.headers = {内容类型":应用程序/json"}

我没有创建新的目标(如 POST 预期的那样),而是返回目标列表(我期望使用 GET).使用pdb,我看到:

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

这是怎么翻过来的?我之前使用过 Python requests 库没有任何问题,所以我不确定我是否遗漏了一些明显的东西,或者(使用较新版本的 Django/Requests)我是否必须设置另一个参数?这是缓存问题吗?有什么调试技巧吗?我试过重新安装请求,并将 Django 回滚到 1.6.5,但没有任何效果......一定很简单.-- 谢谢!

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

只是整合了 Martijn 在这里建议的一些调试信息:

(Pdb) requests.post.__name__'邮政'

进入 requests/api.py > post() 定义:

(Pdb) l88 :param data: (可选) 字典、字节或类似文件的对象要发送到 :class:`Request` 的主体中.89 :param **kwargs: ``request`` 需要的可选参数.90"""91 导入 pdb第92话93 ->返回请求('post', url, data=data, **kwargs)

深入到 request() 方法:

(Pdb) 方法'邮政'(pdb) l43 >>>req = requests.request('GET', 'http://httpbin.org/get')44<响应[200]>45"""46 导入 pdb47 pdb.set_trace()48 ->session = session.Session()49 返回 session.request(method=method, url=url, **kwargs)

在 session.request 中再增加一层:

(424)request()->方法 = builtin_str(方法)(Pdb) 方法'邮政'(pdb) l419 :param cert:(可选)如果是字符串,则为 ssl 客户端证书文件 (.pem) 的路径.420 如果元组, ('cert', 'key') 对.第421话第422话第423话424 ->方法 = builtin_str(方法)425426 # 创建请求.第427话第428话第429话

到方法的末尾,实际发出请求的地方,我的准备"是 POST,但我的响应是 GET:

(Pdb) 准备<PreparedRequest [POST]>(Pdb) n->返回响应(Pdb) 响应<响应[200]>(Pdb) 响应请求<PreparedRequest [GET]>(pdb) l第449话第450话第451话452 resp = self.send(准备,**send_kwargs)453454 ->返回响应455456 def get(self, url, **kwargs):457 """发送 GET 请求.返回 :class:`Response` 对象.458459 :param url: 新 :class:`Request` 对象的 URL.

解决方案

要清楚,每当请求收到重定向(带有特定的状态代码)我们必须对请求执行某些转换.

在这种情况下,当您看到非常意外的情况时,最好的调试技巧是重试您的请求,但使用 allow_redirects=False.这将立即返回 30x 响应.或者,您还可以检查 r.history 以查看是否有任何 30x 响应被遵循.在这种情况下,您可能会看到类似

<预><代码>>>>请求方法'得到'>>>r.历史[<响应[302]>,]>>>r.history[0].request.method'邮政'

我们知道这样做可能会导致用户出现意外行为(就像对您一样),但这是在网络上操作的唯一正确方式.

我希望这能帮助您理解为什么会发生这种情况,而不仅仅是重定向,并希望它为您和其他人提供工具来在未来进行调试.

I am using Python 2.7.5, Django 1.7, requests 2.4.1, and doing some simple testing. However, it seems like when I call requests.post, the method is doing a GET instead.

My code, talking to a RESTful API. Note that the POST command works via Hurl.it with this payload and endpoint:

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()

I am setting the headers to json:

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

Instead of creating a new objective (as expected with a POST), I get a list of objectives back (what I would expect with a GET). Using pdb, I see:

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

How did this get flipped? I have used the Python requests library before with no issues, so I'm not sure if I am missing something obvious or if (with newer versions of Django / Requests) I have to set another parameter? Is this a caching issue? Any tips for debugging? I have tried re-installing requests, and rolling back Django to 1.6.5, but nothing works...must be simple. -- Thanks!

====== UPDATE 1 ========

Just consolidating some of the debug info that Martijn suggested here:

(Pdb) requests.post.__name__
'post'

Stepping into the requests/api.py > post() definition:

(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)

Drilling down into the request() method:

(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)

One more layer, in 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,

Stepping down to the end of the method, where the request is actually made, my "prep" is a POST, but my resp is a 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.

解决方案

To be clear, whenever requests receives a redirect (with a certain status code) we have to perform certain transformations on the request.

In cases like this, when you see something very unexpected the best debugging tips are to retry your request but with allow_redirects=False. This will immediately return the 30x response. Alternatively, you can also check r.history to see if there are any 30x responses that were followed. In this case you probably would have seen something like

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

We know that doing this can cause unexpected behaviour for users (as it just did to you) but it's the only correct way to operate on the web.

I hope this helps you understand why this happened beyond the fact that it was a redirect, and hopefully it gives you and others tools to debug this in the future.

这篇关于Python 请求 POST 执行 GET?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆