我对Flask中的以下行为感到困惑。我确信有一些基本的东西,但我不知道这是一个脚本或服务器问题,所以我发布了我能想到的最短的例子。
该页面有两种方法将数据发布到服务器。一个是通过提交<form>
而另一个是通过侦听Ctrl+V
的脚本来触发的。我认为两者都应该导致最后一次render_template
电话。 但只有第一个。
paste.html
{%if msg %}
{{ msg }}
{% else %}
Waiting
{% endif %}
<form action="/pastetest" method="post">
Dummy<br>
<input type="text" name="foo" value="bar">
<br>
<input type="submit" value="Send info" />
</form>
脚本 收听'粘贴'事件(Ctrl V)并在表单中发布一些虚拟字符串。
document.addEventListener('paste', function (e) {sendform(e);},false);
sendform = function (e) {
var fd = new FormData();
fd.append('data','testing paste');
var request = new XMLHttpRequest();
request.open("POST", "/pastetest");
request.send(fd);
console.log("Sent")
};
Flask python:
@app.route('/')
def index():
return render_template('paste.html',msg="Waiting")
@app.route('/pastetest',methods=['POST'])
def image_upload():
if request.method == 'POST':
print("On the server")
print(request.form)
alldone="All done time=%d" % time.time()
print(alldone)
return redirect(url_for('confirm',msg=alldone))
@app.route('/confirm/<msg>')
def confirm(msg):
print("At confirm",msg)
return render_template("paste.html",msg=msg) #<---should end up here
从控制台我看到数据正在发布并且正在调用confirm
。
127.0.0.1 - - [19/Nov/2017 00:51:42] "GET /confirm/All%20done%20time%3D1511049102 HTTP/1.1" 200 -
但页面仅在提交按钮后呈现。否则它会卡在Waiting
上。
修改: 澄清一下:我需要的只是获取发布的数据(上面只是一个虚拟字符串,但将是剪贴板中的一个blob),用它做一些事情,然后用结果渲染一个模板。最简单的方法是什么?
(我对js / client-server等完全一无所知。只是想为我已经写过的图像分析程序创建一个简单的Web界面。简单的解释赞赏:)
答案 0 :(得分:1)
由于您只是发送XmlHttpRequest
,因此不会呈现您的网页,只有您的浏览器才会呈现回复。
您的JavaScript会向您指定的URL发送POST请求,您可以从日志中看到,但由于您没有对the response to that request执行任何操作,因此没有任何操作。
这会有用......
<form action="/pastetest" method="post">
...因为提交HTML表单时,您的浏览器不仅仅是向action
中的网址发送POST请求,还会将位置更改为该网址并呈现其获得的响应。
您会注意到,在提交HTML表单时,您的浏览器位置栏中的网址确实会发生变化,而在发送XmlHttpRequest
时它不会发生变化。
编辑,总结评论:
在这两种情况下,服务器都会执行函数image_upload
和confirm
,换句话说,从服务器的角度看,它们是等价的,这里的主要区别在于使用XmlHttpRequest方法,响应不是由浏览器自动呈现。
至于问题中描述的目标,让浏览器在两种情况下都呈现结果页面,我们必须考虑一旦得到我们的回复,XmlHttpRequest
案例中发生了什么:
image_upload
和confirm
confirm
函数中的渲染模板位于我们的回复中如果我们不介意confirm
函数执行两次,我们只需将浏览器的window.location
指向请求的the responseURL即可。
当我们这样做时,该函数肯定会被执行两次,它已被执行一次以生成我们得到的响应,并让我们的浏览器转到responseURL(在我们的例子中,这将是对应于confirm
函数的URL),它将再次执行。
如果我们想要阻止这种情况,我们需要另一种解决方案。
一个选项是通知服务器我们不希望在进行初始上传时重定向到呈现的响应页面,而只是想要一个状态信息(我们可以在这里使用HTTP状态代码,例如我们解释status =我们上传的服务器响应应该是我们需要指向浏览器window.location
的地方。
这样,服务器只会执行confirm
一次,因为它不会在我们的XmlHttpRequest的情况下自动重定向我们,而只会告诉我们我们需要去哪里并让责任真正去那里是客户端JavaScript。
这意味着更改我们的服务器端代码,服务器需要识别我们想要的响应类型。我们可以使用两个不同的端点实现此目的,例如我们的上传表单提交为/pastetest
,XmlHttpRequest为/pastetestxhr
。
另一种选择是使用JavaScript从响应中提取部分呈现的模板,并替换当前页面的部分内容,如从页面中删除我们的HTML表单,并将其替换为响应中的成功通知。 / p>
为了方便地执行此操作,我们可能希望使用一些客户端JavaScript库,例如jQuery
。
这也只会执行confirm
一次,因为我们在得到响应后不会将浏览器位置更改为该端点,而是使用我们已有的响应。
此方法不需要更改任何服务器端代码,但在客户端代码中引入了更多复杂性。
第三种选择可能是混合方法,我们通知服务器我们不想要自动重定向,并期望作为响应我们可以在页面中按原样插入HTML片段,而不需要对响应进行任何复杂的解析提取我们想要插入页面的部分。
这个需要一个更复杂的客户端JavaScript(虽然比上面列出的选项2复杂得多),以及服务器端代码更改。
答案 1 :(得分:0)
除非您通过JS告诉浏览器这样做,否则浏览器不会呈现来自XmlHttpRequest的响应。我建议您查看浏览器的“开发工具”,然后在“网络”选项卡下查看。您将在那里看到XHR的回复,但它不会取代内容或浏览器。