我该如何在Python中发送和接收HTTP POST请求?

4

我有两个Python脚本,用来尝试解决如何在Python中发送和接收POST请求的问题:

客户端代码:

import httplib

conn = httplib.HTTPConnection("localhost:8000")
conn.request("POST", "/testurl")
conn.send("clientdata")
response = conn.getresponse()
conn.close()

print(response.read())

服务器:

from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer

ADDR = "localhost"
PORT = 8000

class RequestHandler(BaseHTTPRequestHandler):        
    def do_POST(self):
        print(self.path)
        print(self.rfile.read())
        self.send_response(200, "OK")
        self.end_headers()
        self.wfile.write("serverdata")

httpd = HTTPServer((ADDR, PORT), RequestHandler)
httpd.serve_forever()

问题在于当客户端调用conn.close()时,服务器会在self.rfile.read()上挂起,但是如果在客户端调用conn.close(),那么客户端就无法从服务器接收响应。这会出现这样一种情况:要么从服务器获取响应,要么读取POST数据,但永远都不能同时实现两者。我认为我错过了某些可以解决这个问题的事情。

额外信息:

conn.getresponse()导致客户端挂起,直到从服务器收到响应。看起来只有在服务器函数执行完成后,才能接收到响应。


5
我强烈建议你查看 python requests。如果你决定重新发明轮子,那就是你的事,但请认识到,Python内置的对HTTP的支持是有限的。而Requests则解决了这个问题。 - kojiro
我会尝试一下。即使只是为了理解为什么这看起来如此固有缺陷,我仍然想知道这里发生了什么。 - user573949
2个回答

6
您原始示例存在一些问题。第一个问题是,如果您使用request方法,则应在该调用中包含要发送的消息正文,而不是单独调用send。文档指出,send()可以作为request替代方案

与上述描述的request()方法相比,您还可以使用以下四个函数之一逐步发送请求。

您只需要conn.request("POST", "/testurl", "clientdata")
第二个问题是您尝试读取发送到服务器的内容的方式。self.rfile.read()试图读取从客户端发来的整个输入流,这意味着它将阻塞,直到流关闭。该流将不会关闭,直到连接关闭。您想要做的就是读取客户端发送的确切字节数,仅此而已。您如何知道那是多少字节?当然是通过头部:
length = int(self.headers['Content-length'])
print(self.rfile.read(length))

如果你想进行更高级的测试,我强烈推荐使用python-requests库。此外,如果你要进行的测试不是非常基础,我也建议使用比BaseHTTPServer更好的HTTP框架/服务器(如flask、bottle、tornado等)。


1

虽然已经有了很长时间的回答,但是在搜索中出现了,所以我带来了另一部分的答案。为了防止服务器保持流开放(导致响应永远不会被发送),您应该使用self.rfile.read1()而不是self.rfile.read()


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