- PR -

ブラウザのアドレスバーに残るdoURLについて

1
投稿者投稿内容
NT
会議室デビュー日: 2003/04/01
投稿数: 4
投稿日時: 2003-07-20 17:00
お忙しいところ申し訳ないのですが、質問したいことがあります。

Strutsを用いたWebアプリケーションを作っているのですが、
少々困った現象が起きています。
私の知識不足かもしれませんが、個人的に手も足も出ない
状態になっておりまして、何かアドバイスをいただけたら嬉しいです。
以下に流れを示したいと思います。

JSPファイルA:テーブルのレコードを更新するフォームを持つJSPファイル。
JSPファイルB:テーブルのレコード一覧を表示するJSPファイル。

流れ:
@
JSPファイルAにおいて更新するデータのフォームに値を入力し、submitする。
(<html:form action="/aaa">) 

A
更新処理が終わり、
遷移先JSPファイルであるBが表示される。
ブラウザのアドレスバーに
(http://localhost:8080/home/aaa.do)が表示される。

B
ブラウザの更新ボタンを押下する

C
また@の動作が行われる。(フォームの値は@で入力した値と同じ)

普通はブラウザの更新ボタンなどをBで押下しないと思いますが、
押下した際にCの現象が起きてしまいました。
私はAに来た際にリクエストはガベージコレクションで破棄されると思っていました。
しかし、Eclipseでデバッグをし、B時にリクエストの中身を見ると
@の内容がそのまま入っているのです。
その意味が良く分からず、もしかしたらそういうものなのかも
しれず原因が分からないまま困り果てています...。

Cの現象を出さないためにはシステム自体をフレーム化してしまえば
アドレスバーにdoURLが表示されることも無いのですが...。
何か原因や対処法、経験談、アドバイス等がございましたら
よろしくお願い致します...。

※Strutsのバージョンは1.1
 ブラウザはIE6.0を使用しています。
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2003-07-20 19:23
ご質問の意図がうまく読みとれないのですが、
1)/xxx.do という URL がアドレスバーに表示される
2)post後にリロードすると、同じ2重ポストされてしまう
という2つの現象がありますね。

ユーザは最新の情報を表示しようとリロードするのに、画面更新の際に意図せず DB への
更新処理がもう一度走ってしまうのを防止したいということでしょうか?
これはブラウザが再度ポストしているためであって、前回の request オブジェクトが
残っているわけでわありません。多くのブラウザでは、ポスト後に再ロードボタンを押す
ともう一度ポストして良いかという旨のダイアログが表示されるかと思いますが。


Strutsではこの現象に対するソリューションとして、簡単な2重ポスト防止機構を用意
しています。
これはtokenとよばれるもので、一つのフォームにつきユニークなIDを振って、
そのフォームが既にサブミット済みかどうかを検証する機能です。

Action クラスには generateToken()/isTokenValid()/resetToken() というメソッドが
あり、それぞれトークンの生成、検証、消去を行います。
トークンが生成されるとシステム時間より生成されたユニークなIDがセッション
に自動的にセットされます。
トークンの実体はAction.TRANSACTION_TOKEN_KEY という名前のStringタイプ
の属性です。

トークン生成後 form:form のtaglibをレンダリングする際に自動的にhidden
フィールドとしてフォームに挿入されます。
ActionクラスではvalidateToken()ではそのトークンが有効かどうかを返します。
http://jakarta.apache.org/struts/doc-1.0.2/api/org/apache/struts/action/Acti
on.html

具体的な手順としては以下のようになります。
1)ActionでgenerateToken()、jspへフォワード
2)JSPでトークンのhiddenフィールドを含むフォームを表示
3)post先のActionでisTokenValid()でトークンを検証
4)処理が終了したらresetToken()でトークンを無効化
5)適切なページへフォワード

注意点として、isTokenValid()メソッドはスレッドセーフではないので、
同期処理は自分で行う必要があることに気をつけてください。

以下のような感じになるでしょうか。

ActionForward forward = mapping.findForward("success");
synchronized(session){
if(isTokenValid(request)){
doSomething();
resetToken(request);
}else{
//必要に応じて二重サブミットだったら遷移先をかえたりも。
//forward = mapping.findForward("doubleSubmitted");
}
}
return forward;


>私はAに来た際にリクエストはガベージコレクションで破棄されると思っていました。
余談ですが、リクエストオブジェクトはガベージコレクトされるとは限りません。サーブ
レットコンテナはリソースの効率化のためにリクエストオブジェクトを再利用するように
実装することができます。もちろん適切に初期化するので、以前の情報残っていることは
ありませんが。

[ メッセージ編集済み 編集者: インギ 編集日時 2003-07-20 19:27 ]
NT
会議室デビュー日: 2003/04/01
投稿数: 4
投稿日時: 2003-07-21 16:30
ご返事いただきましてありがとうございます。
かなり有力な情報で嬉しく感じております。

それで、上記のことを試しているのですが、
少々てこずっております^^;。

>1)ActionでgenerateToken()、jspへフォワード
この際にgenerateToken()メソッドを処理するだけで、
次の遷移先JSPには特に値を明示的にプログラミングする必要は
ないと受け取ったのですがよろしいでしょうか?

>2)JSPでトークンのhiddenフィールドを含むフォームを表示
1)から遷移してきたJSPには明示的にhiddenで
トークンの値を持つと書く必要があるのでしょうか?
自動的に作ってくれるということで受け取ったのですが...。

大変お忙しいところ申し訳ないですが、
気が向いたときにでもコメントお願いします><。
1

スキルアップ/キャリアアップ(JOB@IT)