这里缺少两件事:
-
render_template 实际做了什么
- HTTP 流的工作原理
对于 1,答案很简单。 render_template 将获取要渲染的模板的路径以及要渲染模板的上下文并返回一个字符串。所以它不会对请求做任何事情,它只会根据模板和上下文生成一个字符串(在您的代码示例中,它会将这个呈现的字符串存储在data 变量中)。
对于 2,您需要了解的是,当用户向您的 /process 路由发出请求时,它会期望得到响应,并且只有一个响应。
所以你的路由需要决定响应什么:它会是带有一些内容(例如一些 HTML)的200 OK 吗?或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 并且可能会返回某种错误消息以显示给用户。