带有请求的烧瓶损坏的管道

Posted

技术标签:

【中文标题】带有请求的烧瓶损坏的管道【英文标题】:Flask broken pipe with requests 【发布时间】:2012-09-17 11:46:24 【问题描述】:

我想在烧瓶应用中发送本地 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 会导致整个烧瓶应用程序冻结。当我发送终止信号时,我收到了一个损坏的管道错误。有没有办法防止烧瓶在这里结冰?

【问题讨论】:

【参考方案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 成功了

【讨论】:

【参考方案2】:

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

app.run(threaded=True)

但请注意,不建议将 Flask 服务器用于生产用途。从 Flask 1.0 开始,threaded 是默认启用的,你真的想在命令行上使用flask 命令来运行你的应用程序。

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

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

【讨论】:

我以线程方式运行 wsgi 应用程序,但无论如何我得到了 Broken Pipe:app.run(debug=True, threaded=True, host='0.0.0.0', port=8080) @loretoparisi:没有无法诊断的细节。使用您的 app.run() 行和调整后的 curl 命令运行问题中的代码可以正常工作。也许您应该发布一个新问题? thread=True 解决不了这个问题吧? @Martijn Pieters @Uddhav:如果你在 WSGI 服务器下将 Flask 作为 WSGI 应用程序运行,那么app.run() 不会被使用,所以threaded=True 不会有什么不同,不。跨度> 感谢您的解决方案。这个问题真的很困扰我。【参考方案3】:

导致崩溃的错误是fixed in Version 0.12,于 2016 年 12 月 21 日发布。是的!这是许多人一直在等待的重要修复。

来自 Flask 更新日志:

恢复导致开发服务器崩溃的行为更改,而不是返回内部服务器错误(拉取请求 #2006)。

【讨论】:

是的!谢谢你的提示。升级到烧瓶 0.12 解决了这个问题。现在这些错误只是被记录下来而不会导致我的服务器崩溃。【参考方案4】:

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

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

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

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

【讨论】:

+1 在请求处理程序中发出请求在大多数情况下是不好的,对自己的 http 请求...... ick 我遇到了这个问题,因为我正在合并两个以前作为单独进程运行的 Web 服务。两个 Web 服务之间的唯一交互是 POST。我使用蓝图将它们组合到同一个过程中,然后繁荣,它冻结了。因此,需要进行更多重构。 @Corbin 那么对于 TwistedWeb 来说,线程=True 选项在每个请求的多处理和多线程执行方面是否不够?

以上是关于带有请求的烧瓶损坏的管道的主要内容,如果未能解决你的问题,请参考以下文章

带有 PHP 的 APNS 显示 SSL 损坏的管道错误

带有标准输入的 subprocess.Popen.communicate() 的管道损坏

python 处理管道损坏错误(例如,在请求完成之前关闭浏览器)

错误:[Errno 32] 管道损坏

下载带有请求的 zip 文件时,文件最终被损坏

VSTS:如何重新排队损坏的构建和切换代理队列