分享
 
 
 

多重提交处理(二)

王朝other·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

表2当然是一种改善,但我们还是需要一些其他方法。仍然有许多情况会导 致错误。如果用户按下了浏览器的后退键或者刷新了整个网页会怎么样?如果用户的浏览器关闭了javascript的功能或者浏览器不能处理会如何呢?我们还是可以处理这个问题的,但是为了取代防止多重提交,我们需要在后端通过表单处理的服务端小程序处理它们。

为了理解如何解决多重提交问题,我们必须首先理解服务端小程序会话(sessions)机制。每个人都知道,HTTP协议的固有性质中并不对状态(客户端请求信息的历史记录)进行记录。为了处理状态,我们需要一些方法使浏览器能够将当前请求与其他大量请求联系起来。会话(session)程序提供给我们一个解决这个问题的方案。HttpServlet中的方法doGet()和doPost()使用了两个指定的参数:HttpServletRequest和HttpServletResponse。服务端小程序请求参数使我们能够访问会话(session)。会话为访问和存储状态提供了机制。

什么才是会话(session)呢?会话(session)包括很多内容:

状态集——由web服务器管理并且由特定用户所有请求所共享的详细表示描述。

存储空间——通过HttpSession接口至少将HttpServlets所需状态数据和定义存储起来。

在我们具体了解如何使用服务器端方案解决我们的问题之前,我们还需要了解服务端小程序会话(session)的生命周期。与EJB及其他服务端实体一样,会话在生存期中通过一个定义的状态集运行。下图显示了会话的生命周期。Servlet可在三种特定的状态中转换:不存在(does not exist),新建(new),非新建(not new/或使用中in-use)。

a)会话在开始时处于不存在状态。会话从这一状态开始或者由于许多原因而返回到此状态。最主要的原因就是用户以前没有访问过这些状态或者是由于用户脱离(超时)站点或退出使会话被设置为无效。

b)当会话被建立时便会从“不存在”状态进入“新建”状态。新建与非新建状态的区分是非常重要的,因为HTTP协议不记录状态信息。根据servlet详细说明书描述,在客户端返回会话给服务端之前会话不能够进入非新建状态(即从预期会话转变为当前会话)。这样在客户端不知道或者还没有决定加入会话时会话处于新建状态。

c)当会话通过cookie或是重写URL()返回到服务器时,会话就变为“使用中”或“非新建”状态。

d)通过各种get与set方法继续使用会话会使其维持在“使用中”状态。

e)当会话由于长时间没有被使用而超时或显式的被设为无效则会发生图中所示的5以及6所标识的转移。不同应用服务器用不同方式处理超时。BEA公司的WebLogic使应用部署者能够通过与web应用一起打包的特殊部署描述脚本(weblogic.XML)设置会话超时的时限。

现在我们了解了会话的生命周期,那么如何获得一个会话并有效的使用它呢?接口HttpServletRequest提供了两个关于会话的方法:

public HttpSession getSession()返回一个新的会话或一个已存在的会话。

如果提供一个有效的会话ID(可能是通过cookie)则返回一个存在的会话。返回新的会话可能会有许多原因:用户最初的会话(无法提供有效会话ID);会话超过有效时间(提供了会话ID);一个无效的会话(提供了会话ID);或者是明确指出会话无效(提供了会话ID)。

public HttpSession getSession(boolean)可能返回新会话、存在的会话或者空。getSession(true)尽可能返回一个存在的会话。否则创建一个新会话。getSession(false) 尽可能返回一个存在的会话否则返回空。

我们还是只解决了手边一半的问题。我们希望能够跳过会话“新建”状态并自动的转换到会话“使用中”状态。我们能够通过重定向浏览器到处理服务端小程序自动的实现这些。表3把服务端小程序会话逻辑和重定向用户端与有效会话到处理服务端小程序的能力结合在一起。

表3:RedirectServlet.Java

01: package multiplesubmits;

02:

03: import java.io.*;

04: import java.util.Date;

05: import javax.servlet.*;

06: import javax.servlet.http.*;

07:

08: public class RedirectServlet extends HttpServlet{

09: public void doGet (HttpServletRequest req, HttpServletResponse res)

10: throws ServletException, IOException {

11: HttpSession session = req.getSession(false);

12: System.out.println("");

13: System.out.println("-------------------------------------");

14: System.out.println("SessionServlet::doGet");

15: System.out.println("Session requested ID in Request:" +

16: req.getRequestedSessionId());

17: if ( null == req.getRequestedSessionId() ) {

18: System.out.println("No session ID, first call,

creating new session and forwarding");

19: session = req.getSession(true);

20: System.out.println("Generated session ID in Request: " +

21: session.getId());

22: String encodedURL = res.encodeURL("/RedirectServlet");

23: System.out.println("res.encodeURL(\"/RedirectServlet\");="

+encodedURL);

24: res.sendRedirect(encodedURL);

25: //

26: // RequestDispatcher rd = getServletContext().getRequestDispatcher(encodedURL);

27: // rd.forward(req,res);

28: //

29: return;

30: }

31: else {

32: System.out.println("Session id = " +

req.getRequestedSessionId() );

33: System.out.println("No redirect required");

34: }

35:

36: HandleRequest(req,res);

37: System.out.println("SessionServlet::doGet returning");

38: System.out.println("------------------------------------");

39: return;

40: }

41:

42: void HandleRequest(HttpServletRequest req, HttpServletResponse res)

43: throws IOException {

44: System.out.println("SessionServlet::HandleRequest called");

45: res.setContentType("text/Html");

46: PrintWriter out = res.getWriter();

47: Date date = new Date();

48: out.println("<html>");

49: out.println("<head><title>Ticket Confirmation</title></head>");

50: out.println("<body>");

51: out.println("<h1>The Current Date And Time Is:</h1><br>");

52: out.println("<h3>" + date.toString() + "</h3>");

53: out.println("</body>");

54: out.println("</html>");

55: System.out.println("SessionServlet::HandleRequest returning");

56: return;

57: }

58: }

这如何解决我们的问题的呢?测试上面这段代码显示出在11行我们尝试获得一个会话的句柄。

在17行我们通过检测为空的会话ID或检测有效会话ID来确定存在一个有效的会话。如果不存在会话就执行18-29行程序。通过下述方法我们处理多重提交的问题,在19行首先建立一个会话,在22行使用URL编码添加新会话ID,并且在24行重定向我们的服务端小程序到新的URL编码。

不熟悉重写URL的读者可参考15行到23行。一个HttpServlet对象可以重写URL。这个过程将一个会话ID插入到URL。底层的应用服务器能够自动的用编码URL提供给服务端小程序或jsp一个存在的会话。由于这依赖于应用服务器,为了使上面的例子可以运行,你可能需要设置环境使URL能够重写!

总结

在这篇文章中,我们讨论了多重提交问题的许多解决方案。每一个方案都有优点和缺陷。在处理问题时,要清晰的理解和权衡解决方案多方面的优点和缺陷。我们最后的例子有利于解决客户端额外重复的访问和浏览的问题。JavaScript脚本的方法是最好的,但是需要客户端支持才能够运行。和其他任何问题一样,会有一大堆解决方案,每个方案都会有其自己的优缺点。掌握每个方案的优缺点,有利于我们为解决问题作出最好的选择。

matrix开源技术经onjava授权翻译并发布.

如果你对此文章有任何看法或建议,请到Matrix论坛发表您的意见.

注明: 如果对matrix的翻译文章系列感兴趣,请点击oreilly和javaworld文章翻译计划查看详细情况

您也可以点击-fpwang查看翻译作者的详细信息 (出处:http://www.knowsky.com)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有