在Flask请求中发送Flask请求
我正在我的Flask应用中实现一个接口,这个接口接收一系列的HTTP请求,并返回相应的一系列HTTP响应。为了做到这一点,我需要这个接口去调用其他接口,以构建最终的结果。然而,由于Flask在处理原始请求时是阻塞的,它无法处理嵌套的请求,导致应用程序出现死锁。
有没有什么办法可以在Flask中实现请求中的请求,而不会导致死锁呢?
我附上了一段我认为足以说明问题的代码。如果你想看更多的代码,请告诉我,我会分享的。
from requests import Session, Request
def split(request):
multipart = request.stream.read()
boundary = request.content_type.split(';')[1]
prefix = ' boundary"'
suffix = '"'
delimiter = '--%s' % boundary[len(prefix)+1:-len(suffix)]
subrequests = [s.lstrip() for s in multipart.split(delimiter)]
for sub in subrequests:
status_line, _, more_lines = sub.partition('\n')
method, path, version = status_line.split()
headers, _, body = more_lines.partition('\n\n')
url = 'http://localhost:3000' + path
return Request(method, url, headers=headers, data=body)
@app.route('/batch', methods=["GET", "POST"])
def batch():
subrequests = split(request)
session = Session()
responses = []
for sub in subrequests:
response.append(s.send(sub.prepare())) # Deadlock!
我考虑了两个可能的解决方案,但都不太满意:
不要发起完整的请求。相反,直接调用映射到相关接口的函数(url_for)。我对这种方法不满意,因为嵌套请求有自己的头信息和cookie,而这个方法忽略了这些。此外,'before_request'和'after_request'处理程序中的代码不会自动调用。
运行多个应用实例。这可以解决问题,但会让我的服务暴露在一个相对简单的拒绝服务攻击(DoS)下。如果我有X个实例在运行,攻击者只需要用X个不同的请求来攻击我的服务,就能导致死锁。
谢谢。
2 个回答
4
知道Flask的内部服务器不适合用在生产环境中,所以如果只是为了开发使用,可以在运行应用的时候加上一个参数,设置为threaded=true。
app.run(debug=True, threaded=True)
3
这个问题出现是因为你在使用Flask的开发服务器。这个服务器不适合用在生产环境中。
在生产环境里,你应该使用一个应用服务器,比如uWSGI、GUnicorn、Tornado等,可能还会加一个网页服务器,比如NGINX或Apache,来帮助管理和分配连接给工作进程,这样可以在一定程度上保护你的应用免受拒绝服务攻击(虽然不能完全防止,但在很多情况下是可以接受的)。