在Flask请求中发送Flask请求

5 投票
2 回答
3575 浏览
提问于 2025-04-18 08:23

我正在我的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!

我考虑了两个可能的解决方案,但都不太满意:

  1. 不要发起完整的请求。相反,直接调用映射到相关接口的函数(url_for)。我对这种方法不满意,因为嵌套请求有自己的头信息和cookie,而这个方法忽略了这些。此外,'before_request'和'after_request'处理程序中的代码不会自动调用。

  2. 运行多个应用实例。这可以解决问题,但会让我的服务暴露在一个相对简单的拒绝服务攻击(DoS)下。如果我有X个实例在运行,攻击者只需要用X个不同的请求来攻击我的服务,就能导致死锁。

谢谢。

2 个回答

4

知道Flask的内部服务器不适合用在生产环境中,所以如果只是为了开发使用,可以在运行应用的时候加上一个参数,设置为threaded=true。

app.run(debug=True, threaded=True)
3

这个问题出现是因为你在使用Flask的开发服务器。这个服务器不适合用在生产环境中。
在生产环境里,你应该使用一个应用服务器,比如uWSGI、GUnicorn、Tornado等,可能还会加一个网页服务器,比如NGINX或Apache,来帮助管理和分配连接给工作进程,这样可以在一定程度上保护你的应用免受拒绝服务攻击(虽然不能完全防止,但在很多情况下是可以接受的)。

撰写回答