55

我想在烧瓶应用程序中发送本地 REST 请求,如下所示:

from flask import Flask, url_for, request
import requests

app = Flask(__name__)

@app.route("/<name>/hi", methods=["POST"])
def hi_person(name):
    form = {"name": name}
    return requests.post(url_for("hi", _external=True), data=form)

@app.route("/hi", methods=["POST"])
def hi():
    return 'Hi, %s!' % request.form["name"]

发送curl -X POST http://localhost:5000/john/hi会导致整个烧瓶应用程序冻结。当我发送终止信号时,我收到了一个损坏的管道错误。有没有办法防止烧瓶在这里结冰?

4

4 回答 4

114

在能够处理并发请求(可能是gunicornuWSGI )的适当 WSGI 服务器下运行您的烧瓶应用程序,它会工作。在开发过程中,在 Flask 提供的服务器中启用线程:

app.run(threaded=True)

但请注意,不建议将 Flask 服务器用于生产用途。从 Flask 1.0 开始,threaded默认情况下是启用的,并且您flask确实希望在命令行上使用该命令来运行您的应用程序。

发生的情况是,使用请求您正在向您的烧瓶应用程序发出第二个请求,但由于它仍在忙于处理第一个请求,因此在完成第一个请求之前它不会响应第二个请求。

顺便说一句,在 Python 3 下,socketserver 实现更优雅地处理断开连接并继续服务而不是崩溃。

于 2012-09-25T22:19:58.240 回答
19

这里有几件事在起作用,我将尝试一次解决它们。

首先,您可能正在使用玩具开发服务器。该服务器有很多限制;这些限制中最主要的是它一次只能处理一个请求。当您在第一个请求期间创建第二个请求时,您将锁定您的应用程序:该requests.post()函数正在等待 Flask 响应,但 Flask 本身正在等待post()返回!这个特定问题的解决方案是在多线程或多进程环境中运行您的 WSGI 应用程序。为此,我更喜欢http://twistedmatrix.com/trac/wiki/TwistedWeb,但还有其他几个选项。

顺便说一句……这是一种反模式。您几乎肯定不想为了在两个视图之间共享某些功能而调用 HTTP 请求的所有开销。正确的做法是重构以拥有一个单独的函数来完成该共享工作。我无法真正重构您的特定示例,因为您所拥有的非常简单,甚至不值得两个视图。你到底想建造什么?

编辑:一条评论询问玩具标准库服务器中的多线程模式是否足以防止死锁发生。我会说“也许”。是的,如果没有任何依赖关系阻止两个线程取得进展,并且两个线程都取得了足够的进展来完成它们的网络任务,那么请求将正确完成。但是,确定两个线程是否会相互死锁是无法确定的(证明被忽略为钝),我不想肯定地说 stdlib 服务器可以正确地做到这一点。

于 2012-09-25T22:25:17.700 回答
5

导致崩溃的错误已在 2016 年 12 月 21 日发布的 0.12 版本中修复。是的!这是许多人一直在等待的重要修复。

从 Flask 更新日志:

  • 恢复导致开发服务器崩溃的行为更改,而不是返回内部服务器错误(拉取请求 #2006)。
于 2017-03-20T16:25:10.393 回答
-1

我对 post 方法也有同样的问题,一般来说我的 post 方法什么也没做,这就是为什么会出现这个问题

return _socket.socket.send(self._sock, data, flags) urllib3.exceptions.ProtocolError:
('Connection aborted.', BrokenPipeError(32, 'Broken pipe'))

if request.method == 'POST':
    print(len(request.data))
return 'dummy'

print成功了

于 2019-08-28T12:04:43.547 回答