今天重新认识了Post/Redirect/Get pattern, 感谢hip-hop的session, 一下帮助我理清了概念和思路.
谈到pattern,首先要清楚它为了什么而产生: PRG (参见链接1)是为了解决web页面的double submit问题而提供的一种方案.
1. double submit problem
上下文: 用户在browser中的pageA页面完成输入,点击了提交按钮,进入pageB页面,提示"提交成功". 这时, 若分别出现下列三种case:
1> 重新载入或刷新pageB;
2> 点击浏览器的后退按钮,接着点击前进按钮;
3> 点击浏览器的后退按钮退回到pageA,再点一回提交按钮;
对于没有考虑过这种问题而直接开发的网站,会出现什么情况呢?
case 1和case 2会由浏览器弹出一个小窗口,提示大意如"可能重复提交页面,是否继续?"的询问,如果选择了yes,那么前面的提交行为会再做一次;而case 3属于你主动地再一次提交. 也就是说,如果是买东西的话,那你已经重复买到了第二份! 这就是所谓的double submit.
究起实质, 是由于submit pageA和点击提交按钮共用了同一个服务器请求, 而这恰恰是一个POST请求, 在页面被重复提交的背后, POST请求也被多次发送, 导致server上错误地多次执行了添加或更改数据的行为. 图1解释了double submit问题.
图 1 Double Submit Problem
2. PRG solusion
应该想到,用户的这类如"后退再前进"或刷新的行为, 应当视为对历史结果或页面的查看, 并无再次提交之意.
解决问题的一种思路就是将用户点击提交按钮从而发出POST请求, 页面提交跳转和显示结果页面这三个行为分离开. PRG正是遵循这种思路, Client用POST方法请求Server响应数据变更, Server用Redirect方法将response指定到另一个URL上的结果页面, Client所有对页面显示的请求都用GET方法告知Server. 解决方案如图2所示. 这样, "后退再前进"或刷新页面的行为都发出的是GET请求, 从而不会对server产生任何数据更改的影响, double submit problem得以解决.
图2 PRG solusion
Basic principles:
* 不要用一个页面直接作为POST请求的响应结果, 你会给习惯"后退再前进"的人留下resubmit难题.
* 在处理完POST请求之后, redirect到另一个URL页面, 刷新页面的人就只能看到它.
* 用GET而不是POST去请求一个页面的显示, 当你需要的仅仅是显示的结果.
请注意:
* 后退到页面内再点击提交按钮来提交页面的行为,依然被认为是用户自愿的提交.
* 第一次提交后, Server的response正常完成之前的再次提交若未被所应用的框架阻止的话, 它会被Server认为是另一个正常提交.
3. IsPostBack
值得一提的是, .Net WebForm中, 常在Page_Load方法中使用Page.IsPostBack属性来判断对当前Form的请求是第一次or非第一次, 这和本文讨论的问题不完全一致: Asp.net提供了支持服务器端事件的控件, 同时还支持控件的AutoPostBack行为, 故会多次发出对当前Form的请求, 而IsPostBack提供了加载页面时的一个逻辑分支. IsPostBack属性在多种情况下的取值规则可参见链接2 .
附参考链接:
[1] http://en.wikipedia.org/wiki/Post/Redirect/Get
[2] http://www.cnblogs.com/hobe/archive/2008/04/06/1139031.html
http://blog.csdn.net/shaobo_wu/article/details/5854448