阻止表单重新提交
在Web开发中,为了防止某些重复的表单提交,需要使用PRG(Post/Redirect/Get)模式,你只实现了PRG中的P,需要进行重定向(Redirect)。
PRG是一种Web开发设计模式,可以防止一些重复的表单提交,具体流程如下:提交表单(Post Request 1)-> 重定向(Redirect)-> 获取数据(Get Request 2)
底层实现机制如下:
重定向状态码 - HTTP 1.0 使用HTTP 302或HTTP 1.1 使用HTTP 303
带有重定向状态码的HTTP响应还会在location头字段中提供一个URL。由于这个编码的响应,用户代理(如Web浏览器)被邀请进行第二个请求,该请求与原始请求完全相同,只是指定了location字段中的新URL。
重定向状态码的目的是确保在这种情况下,Web用户的浏览器可以安全地刷新服务器响应,而不会导致初始的HTTP POST请求被重新提交。
双重提交问题如下图所示:
[![Double Submit Problem](https://i.stack.imgur.com/OTPOD.png)](https://i.stack.imgur.com/OTPOD.png)
PRG解决方案如下图所示:
[![Post/Redirect/Get Solution](https://i.stack.imgur.com/tFujj.png)](https://i.stack.imgur.com/tFujj.png)
如果在重定向后用户点击浏览器的返回按钮,会出现"确认表单重新提交"的弹窗吗?我猜即使确认弹窗不再显示,页面1上的POST请求仍然会再次提交相同的数据,用户将再次被重定向到页面2。我有一系列的表单,form1,form2,form3,如何无缝地从form"n"返回到form"n-1"?
随机问题:你在哪里学习了PRG设计模式?
在Chrome浏览器上,发送location头文件的PHP文件甚至不会显示在浏览器的历史记录中,所以返回按钮只会回到表单页面。
重定向后如何获取数据?例如,当我将数据提交到/some_url并重定向到/some_url,这会生成一个GET请求。我怎么知道/some_url的响应应该是什么?/some_url是通用的,并不包含像/some_url/
你需要自己创建。例如,POST请求可以用于插入客户数据,而GET请求可以用于显示成功插入的数据。你可以展示这些数据,这些数据实际上就是表单数据,或者通过从数据库中获取该客户的数据来重用客户页面的视图,通过使用插入成功后收到的客户ID。
但我同意Konkov的解决方案,解决方案在这里:[solution](https://stackoverflow.com/a/47247434/4632019)
防止表单重复提交的问题通常是因为用户在刷新页面时重新提交了表单数据,下面是两种解决方法:
方法1:使用AJAX + 重定向
使用jQuery或类似的工具在后台将表单数据发送到Page2,同时用户仍然可以看到Page1。在成功提交后,将浏览器重定向到Page2。
方法2:表单提交后重定向到自身
这是论坛上常用的技术。Page1上的表单将数据提交到Page2,Page2处理数据并执行必要的操作,然后对自身进行HTTP重定向。这样,浏览器记住的最后一个动作是对Page2的简单GET请求,因此刷新页面时不会重新提交表单。
方法2的变体是重定向到另一个页面。例如,你可以将数据POST到example.com/save.html,保存完成后重定向到example.com/list.html。
使用方法1时,我会使用名为BlockUI的jQuery插件,以便让客户端知道有操作正在进行。
但是,使用方法2时,如果刷新页面时仍然要求重新提交表单,你确定HTTP重定向是否正常工作?打开网络检查器/ Firebug/你的浏览器提供的检查出站HTTP请求的工具,并查看HTTP调用。你应该看到第一个HTTP调用(提交表单数据)使用POST方法进行,返回带有Location头部指向自身的HTTP代码301,然后立即应该看到使用GET方法对同一页面进行的另一个HTTP请求。
在我的情况下,Page1将数据提交到Page2,Page2处理数据并显示一个带有传递给模板的值的页面。重定向应该发生在哪里?页面没有GET请求。
在这种情况下,Page1应该将数据提交到Page2,Page2应该处理数据,但不返回实际的HTML(从模板中获取),而是使用GET方法对自身进行HTTP重定向,或者 - 如果它不接受GET请求 - 对能够接受GET请求的Page3进行HTTP重定向。
如果更新过程很慢,在我们执行重定向之前用户仍然可以点击页面刷新,所以AJAX是唯一一种可靠的方法。
无法同时使用两种方法,我的GET和POST的URL是相同的。当使用GET访问URL时,显示Page1,当使用POST访问URL时,显示Page2。如果我重定向到自身,Page2将变为Page1。