Python Web服务器:如何异步处理请求

3 投票
3 回答
3697 浏览
提问于 2025-04-16 11:42

我需要创建一个Python中间件,完成以下几个任务:

a) 接受来自多个客户端的HTTP GET/POST请求。

b) 修改这些请求,并将它们发送到一个后端的远程应用程序(通过套接字通信)。我对这个远程应用程序没有任何控制权。

c) 接收后端应用程序处理后的结果,并将这些结果返回给请求的客户端。

现在,客户端期望的是同步请求/响应的场景。但是后端应用程序并不是同步返回结果的。也就是说,有些请求处理的时间比其他请求要长得多。因此,

客户端1:发送HTTP请求C1 --> 获取响应R1

客户端2:发送HTTP请求C2 --> 获取响应R2

客户端3:发送HTTP请求C3 --> 获取响应R3

Python中间件以某种顺序接收到这些请求:C2、C3、C1。然后按照这个顺序将它们发送到后端(作为非HTTP消息)。后端以混合的顺序返回结果R1、R3、R2。Python中间件应该将这些响应打包成HTTP响应对象,并将响应发送回相应的客户端。

有没有示例代码可以实现这种行为?Python似乎有大约20种不同的网络框架,我对哪个框架最适合这个场景感到困惑(我希望选择尽可能轻量的框架... 我觉得Django太重了... 我试过Bottle,但不太确定如何在这个场景下编程)。

================================================

更新(基于下面的讨论):请求有一个请求ID。响应有一个响应ID(应该与对应的请求ID匹配)。中间件和远程后端应用程序之间只有一个套接字连接。虽然我们可以维护一个{request_id : ip_address}的字典,但问题在于如何构造一个HTTP响应对象给正确的客户端。我猜测,使用线程可能会解决这个问题,每个线程维护自己的响应对象。

3 个回答

0

最终,你需要把客户端的同步HTTP请求-响应协议,转变为后端的异步排队/消息协议。这样你有两个选择:第一,等到后端没有未处理的工作时再处理请求;第二,写一个程序,把后端的响应和对应的请求关联起来(可以用字典来存储请求)。

一种方法是让你的服务器在一个线程中运行,同时在另一个线程中处理后端的事情(可以参考这个链接... 在后台运行Python HTTPServer并继续执行脚本),或者你可以看看aiohttp这个库(https://docs.aiohttp.org/en/v0.12.0/web.html)。

3

引用你的评论:

这个中间件使用一个持久的单一套接字连接到后端。所有来自中间件的请求都是通过这个单一的套接字转发的。客户端在发送请求时会附带一个请求ID。响应ID应该和请求ID匹配。那么问题是:中间件(网络服务器)是如何跟踪哪个请求ID属于哪个客户端的呢?我的意思是,中间件里的CGI脚本有没有办法创建一个包含元组的数据库,一旦响应ID匹配,就可以把HTTP响应发送到clientip:clienttcpport?

这样在中间件中处理所有这些事情有什么特别的原因吗?如果更合适的话,你应该可以在装饰器或其他地方完成这些操作。

无论如何,你需要维护一个全局的并发字典(扩展 dict 并使用 threading.Lock 来保护它)。在接收到新请求时,把给定的请求ID作为键,关联到相应的客户端(发送者)。每当后端响应时,从这个字典中获取客户端,并删除这个条目,以免它永远累积下去。

更新:有人已经为你扩展了字典 - 请查看 这个答案

4

别再纠结框架了。这种任务正好适合用asyncore模块。这个模块可以让你进行基于事件的网络编程:当某个套接字(socket)准备好数据时,它会调用你指定的处理函数。这样,你就不需要为了等待某个套接字的数据而创建线程,省去了繁琐的步骤。虽然你需要自己实现HTTP处理的部分,但网上有很多例子可以参考。另外,你也可以使用uwsgi的异步功能,这样可以让你的应用和现有的网络服务器结合起来,不过它默认不和asyncore兼容——不过让它们一起工作并不难。具体选择要看你的需求。

撰写回答