Python httplib and POST

7
我目前正在处理由别人编写的代码,它使用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的版本。
请不要建议将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”,在库的常规使用中被省略了。愚蠢的我。


2
顺便提一下,如果您认为将不断调试此事,请安装Wireshark并使用它来窥探实际传输的内容。 - Darien
谢谢,一开始我并不相信,但它确实帮我找到了解决方案。再次感谢。 - julx
服务器代码中有如下设置: response.set_header('Access-Control-Allow-Origin', '*')。 - user1610611
3个回答

6
putrequest方法不会自动添加Content Length头部信息,您需要手动添加或使用request方法。
for循环之前将以下代码添加到您的代码中:
headers['Content-Length'] = "%d"%(len('[{"id":"route"}]'))

5
尝试添加以下内容:
conn.set_debuglevel(1)

将以下代码添加到您的代码中,以便您可以看到实际发生的情况。


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头。

试着让你的代码更像是功能性的样例,并且理解两者之间调用的差别。


1
是的,我确实阅读了API文档,一切看起来都很好。问题在于它并不好。通过其他方式发出的相同请求 - 比如浏览器或另一个库 - 都能正常工作。删除“接受”标头并没有改变任何内容。你从API复制粘贴的示例完全在做不同的事情。它不是POST请求,也没有尝试上传消息正文。 - julx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接