其中isTokenValid()和saveToken()都是org.apache.struts.action.Action類中的方法,而具體的Token處理邏輯都在org.apache.struts.util.TokenProcessor類中。Struts中是根據用戶會話ID和當前系統時間來生成一個唯一(對于每個會話)令牌的,具體實現可以參考TokenProcessor類中的generateToken()方法。
不知道大家有沒有注意到這樣一個問題,因為Struts是將Token保存在Session的一個屬性中,也就是說對于每個會話服務器端只保存而且只能保存一個最新Token值。對于這一點,我的同事就提出了疑問:那如果我在同一個會話中打開兩個頁面,那么后提交的那個頁面肯定不能提交成功了。他還給出了一個實際的例子:比如現在需要把兩個客戶A和B的地址都改為某個值,那用戶就可能同時打開兩個頁面,修改A,修改B,提交A,提交B,按照Struts中的處理邏輯,B的修改提交就肯定不能成功,但是這個提交操作對于用戶來說并不存在操作不正確的地方。
在這里,可能有人要問:怎么可能在同一個會話中打開兩個頁面呢?重新打開一個IE瀏覽器不是重新開始了一個會話嗎?不錯,這種情況下是兩個會話,不存在任何問題。但是,你還可以通過菜單“文件”-“新建”-“窗口”(或者快捷鍵Ctrl+N)來復制當前窗口,這個時候你會發現該頁面與原有頁面同處在一個會話當中。其實,能夠發現這個問題得歸功于我的那位同事對IE習慣性的操作方法。
這下我的那位同事不滿意啦!他于是開始動手修改Struts中的實現方式,讓每個頁面(至少某類頁面)在服務器端都保存有一個唯一的Token值。這樣,前面所講的客戶A,B同時修改的限制就不存在了。但是不久,我的那位同事就開始意識到他正在走向一條危險的道路。首先,如果每個頁面都在服務器端保存一個Token值,則服務器端保存的數據量將越來越大。而且,如果考慮這種同一個會話中打開多個頁面的情況的話,就好像打開了潘多拉魔盒,將會給自己帶來無窮無盡的麻煩。比如,首先打開頁面P1,然后利用Ctrl+N得到頁面P2,P1提交,P2提交,目前為止一切正常。但是如果此時,在P1,P2中點擊“后退”按鈕,然后再提交P1,P2呢,情況會是怎樣?如果在P2中提交完后執行其它操作,而在P1中回退后提交,情況又是怎么樣呢?如果有P1,P2,P3,那情況又是如何呢?太復雜啦!我想你也會和我們有同感,你需要考慮許多種可能的組合,而且有的時候結果并不是你想象中的那樣簡單。
延伸閱讀
文章來源于領測軟件測試網 http://www.kjueaiud.com/