Python httplib 和 POST

7 投票
3 回答
47804 浏览
提问于 2025-04-16 19:21

我现在在处理一段别人写的代码。这段代码使用了httplib来向服务器发送请求。所有的数据格式都很正确,比如消息体、头部值等等。

问题是每次它尝试发送一个POST请求时,数据确实在客户端可以看到,但服务器却收不到。我查看过这个库的说明,使用方法看起来是对的。

提取出来的库调用如下:

import httplib

conn = httplib.HTTPConnection('monkeylabs.pl', 80)
conn.connect()
request = conn.putrequest('POST', '/api/snippet/')
headers = {}
headers['Content-Type'] = 'application/json'
headers['User-Agent'] = 'Envjs/1.618 (SpyderMonkey; U; Linux x86_64 2.6.38-10-generic;  pl_PL.utf8; rv:2.7.1) Resig/20070309 PilotFish/1.3.pre03'
headers['Accept'] = '*/*'
for k in headers:
    conn.putheader(k, headers[k])
conn.endheaders()

conn.send('[{"id":"route"}]')

resp = conn.getresponse()
print resp.status
print resp.reason
print resp.read()

conn.close()

这是不是一个已知的问题?我用的是Python 2.7。不太确定怎么检查httplib的版本。

请不要建议我换成其他库,除非是类似的(比如httplib2)。如我所说,这段代码不是我写的,而且比我刚刚贴的内容要复杂得多。如果要重构代码会造成很大的麻烦。我希望能找到一些可靠的解决办法。

编辑

调试输出:

send: 'POST /api/snippet/ HTTP/1.1\r\nHost: monkeylabs.pl\r\nAccept-Encoding: identity\r\nContent-Type: application/json\r\nAccept: */*\r\nUser-Agent: Envjs/1.618 (SpyderMonkey; U; Linux x86_64 2.6.38-10-generic; pl_PL.utf8; rv:2.7.1) Resig/20070309 PilotFish/1.3.pre03\r\n\r\n[{"id":"route"}]'
reply: 'HTTP/1.0 201 CREATED\r\n'
header: Date: Fri, 10 Jun 2011 23:54:00 GMT
header: Server: WSGIServer/0.1 Python/2.7.1+
header: Vary: Cookie
header: Content-Type: application/json
header: Content-Length: 0
201
CREATED

注意,回复后的信息实际上是关于服务器的回复,而不是请求本身,在这个情况下请求是空的。主要原因是请求体本身是空的,我可以通过获取日志来观察到这一点:

[11/Jun/2011 01:54:00] "POST /api/snippet/ HTTP/1.1" 201 0

还有这三行:

``
<QueryDict: {}>
<QueryDict: {}>

来自:

print '`%s`' % request.raw_post_data
print request.GET
print request.POST

在Django服务器上。所以看起来它尝试发送消息体,但最后并没有发送。

编辑(2)

好的,我做了个转储,确实告诉我在从浏览器发送的消息中有一个额外的参数叫做'Content-Length',而在这个库的常规用法中被省略了。真是我太傻了。

3 个回答

0

你有没有查看过httplib的文档?httplib是Python的一个标准库,而Python的在线文档也很不错,你可以在这里找到:http://docs.python.org/library/httplib.html

那页上的例子是这样的:

>>> import httplib, urllib
>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
>>> headers = {"Content-type": "application/x-www-form-urlencoded",
...            "Accept": "text/plain"}
>>> conn = httplib.HTTPConnection("musi-cal.mojam.com:80")
>>> conn.request("POST", "/cgi-bin/query", params, headers)
>>> response = conn.getresponse()
>>> print response.status, response.reason
200 OK
>>> data = response.read()
>>> conn.close()

你的例子看起来比这个要复杂,如果你看看API文档,比如putrequest的部分,你会发现你在示例中用错了。具体来说,它默认会自动添加Accept头。

试着让你的代码更像那个功能示例,同时也要理解你自己代码和工作示例中使用的调用。

6

putrequest 方法不会自动添加内容长度的头信息,你需要自己添加,或者使用 request 方法。

在你的代码中,for 循环之前加上这个:

headers['Content-Length'] = "%d"%(len('[{"id":"route"}]'))
5

试着在你的代码里加上:

conn.set_debuglevel(1)

这样你就能看到实际发生了什么。

撰写回答