我正在尝试使用Response对象时捕获异常。我的用例是我要像official documentation中所述流数据,并且在获取要流的数据时可能会出现异常:
# test.py
from flask import Flask, Response, jsonify
import werkzeug
app = Flask(__name__)
@app.route("/")
def hello():
def generate():
raise Exception
for i in range(0,10):
yield '1'
try:
return Response(generate())
except Exception:
return jsonify("error") # expected this but instead 500 server error is returned
if __name__ == '__main__':
app.run()
然后我运行服务器并请求数据时,我希望看到“错误”,但会显示Flask发出的“内部服务器错误”消息。
FLASK_APP=test.py flask run
curl http://localhost:5000/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to
complete your request. Either the server is overloaded or there is
an error in the application.</p>
以某种方式引发异常,因为我们可以在stdout中看到它,但是不会被Flask捕获。 我还试图通过设置werkzeug服务器的passthrough_errors选项来确保不捕获异常。然后在Werkzeug中不会捕获异常,例如here或here。不幸的是,这没有帮助在上面的Flask应用程序中捕获它:
app.run(passthrough_errors=True)
flask的输出--version:
Flask 1.0.2
Python 3.7.0 (default, Aug 22 2018, 15:22:33)
[Clang 9.1.0 (clang-902.0.39.2)]
更新: 当我不使用流媒体时,也会发生此问题:
from flask import Flask, Response, jsonify
app = Flask(__name__)
@app.route("/")
def hello():
try:
return Response(2)
except Exception as error:
return jsonify({'error': error})
if __name__ == '__main__':
app.run(passthrough_errors=False)
在Flask端引发TypeError,因为Integer不可迭代,但未捕获到异常。
FLASK_APP=test.py flask run
curl http://localhost:5000/
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to
complete your request. Either the server is overloaded or there is
an error in the application.</p>
答案 0 :(得分:0)
这与发生器功能有关,与烧瓶无关。
def check_positive(x):
if isinstance(x, (datetime.timedelta, np.timedelta64)):
return x.total_seconds() > 0
else:
return x > 0
将返回一个生成器,而不是数字1或异常! (尝试打印def generate():
raise Exception
yield '1'
)。
还尝试将generate()
更改为yield
,并检查差异。
但是现在解决方案:
return
答案 1 :(得分:0)
让我们更改代码,然后再次运行:
@app.route("/")
def hello():
def generate():
raise Exception
yield '1'
try:
resp = Response(generate())
data = resp.data
return resp
except Exception:
return jsonify("error") # expected this but instead 500 server error is returned
此代码将正确返回“错误”,前一个代码也“正确”引发500服务器错误。要了解原因,您必须考虑执行流程。在您的初始代码中,return Response(generate())
将立即返回而不执行生成器函数。消费者(在这种情况下可能是werkzeug)将尝试读取data
或类似的属性,这将导致生成器运行。到那时,您的函数已经执行,并且当然不会发生任何异常,因为您将返回包装在Response
中的生成器。希望这会有所帮助。
上面的代码仅演示了该问题,并说明了为什么原始代码未捕获异常。如果在流恕我直言的中间出现错误,则应用程序应给出500个服务器错误并死亡。但是,将异常移至生成器将使您捕获此类错误:
@app.route("/")
def hello():
def generate():
try:
raise Exception('some error')
for i in range(0,10):
yield '1'
except Exception as e:
yield str(e)
return Response(generate())
而且您不能使用jsonify
,因为生成器正在应用程序上下文之外使用。
答案 2 :(得分:0)
如果您来自网络搜索,是因为生成器中的异常未在客户端呈现,那是因为响应中的生成器模式实际上是HTTP分块流。这种技术导致一个HTTP响应被分块发送到客户端。首先返回HTTP响应代码(例如200表示成功)。因此,如果以下任何块触发代码中的异常,则Flask无法将其返回给浏览器。