我想创建一个等待页面,我可以在执行一些长函数之前渲染这个页面。当它完成后,它将重定向到成功页面作为回报。这是一个简单的代码示例
@app.route("/process", methods=['GET', 'POST'])
def process():
with app.app_context():
data = render_template('waiting.html')
### .. Do something long and have to wait .. ###
# e.g. sleep a few seconds
return redirect(url_for('success'))
发生的是data = render_template('waiting.html')
行似乎没有被执行。我看到的是空白屏幕一段时间(因为它是下面的处理功能)。并且,当它完成时,它会按预期显示成功页面。
这似乎是一项简单的任务,之前已经提出了许多问题。但这些解决方案并不适用于我。我的目标只是在执行任务之前使模板显示出来。这样用户就会看到他们的请求正在进行中。
这是我尝试过的。
如果我误解了Flask的概念,请告诉我。 谢谢!
答案 0 :(得分:2)
这里有两件事你不知道:
render_template
实际做什么对于1,答案很简单。 render_template
将获取要呈现的模板的路径以及要使用该模板呈现模板的上下文,并返回一个字符串。所以它不会对请求做任何事情,它只会根据模板和上下文生成一个字符串(在你的代码示例中,它会将这个呈现的字符串存储在data
变量中)。
对于2,您需要了解的是,当用户向您的/process
路由发出请求时,它会产生响应,并且只有一个响应。
所以你的路线需要决定要回应什么:它会是一个带有一些内容的200 OK
(例如某些HTML)吗?还是301 Redirect
会指示用户的浏览器转到另一个页面?您不能同时拥有这两个响应,因为它违反了协议。
为了获得您想要的体验,您必须指示用户的浏览器向您的服务器发出多个请求。您可以使用一些策略,但最简单的策略可能是使用Ajax。
我们的想法是,您的初始路线只会呈现waiting.html
页面,但会带来扭曲。在页面中,您将添加一些JavaScript代码,这些代码将Ajax请求发送到将执行实际长时间运行作业的其他路由。
所以现在你有两条路线:
@app.route("/process", methods=['GET', 'POST'])
def process():
if request.method == 'GET':
return render_template('waiting.html')
if request.method == 'POST':
### .. Do something long and have to wait .. ###
# e.g. sleep a few seconds
return 'done'
(即使它只是一种方法,它们基本上是两条路线:GET /process
和POST /process
)
您网页中的JavaScript将如下所示:
var request = new XMLHttpRequest();
request.open('POST', '/process');
request.onload = function() {
if (request.status === 200 && request.responseText === 'done') {
// long process finished successfully, redirect user
window.location = '/success';
} else {
// ops, we got an error from the server
alert('Something went wrong.');
}
};
request.onerror = function() {
// ops, we got an error trying to talk to the server
alert('Something went wrong.');
};
request.send();
(或者如果您使用jQuery)
这样做会在后台向您的服务器发起另一个HTTP请求,该请求将启动该长时间运行的作业,并将作为响应接收文本done
。发生这种情况时,它会将用户重定向到/success
页。
现在,重要的是要记住这很简单,你需要记住一些事情:
这些Ajax请求中的每一个都将阻止与您的服务器的连接,如果您使用像gunicorn这样的东西,那么它将是一个完整的工作者。因此,如果您的处理时间过长,或者您有很多并发用户访问此路由,那么您的服务器将会非常过载。
您需要正确处理错误。在我的示例中,我始终使用done
(这是默认状态代码)返回200 OK
,但如果处理中出现问题,您将返回something different并可能返回某种错误消息向用户显示。
答案 1 :(得分:0)
不会退回等待data
。根据{{3}}提到的
yield
尝试此解决方案
from flask import Response, stream_with_context
@app.route("/process", methods=['GET', 'POST'])
def process():
def generate_output():
with app.app_context():
yield render_template('waiting.html')
### .. Do something long and have to wait .. ###
# e.g. sleep a few seconds
# Later to find that we Can't yield redirect
# yield redirect(url_for('success'))
return Response(stream_with_context(generate_output()))
更新:很抱歉发现yield
只能用于将数据流式传输到一个页面而不能用于重定向。