[解決済み] javax.faces.application.ViewExpiredException: ビューを復元できませんでした
質問
私は、コンテナ管理されたセキュリティで簡単なアプリケーションを書きました。問題は、私がログインし、ログアウトした別のページを開いたときに、最初のページに戻り、任意のリンクなどをクリックするか、ページを更新すると、この例外が発生します。私はログアウトし、セッションが破壊されているので、それは正常だと思います(または多分そうではありません:)。ユーザーを例えばindex.xhtmlやlogin.xhtmlにリダイレクトして、そのエラーページやメッセージを見ずに済むようにするにはどうしたらよいでしょうか?
言い換えれば、ログアウト後に他のページを自動的にindex/loginページにリダイレクトするにはどうすればよいでしょうか?
ここにあります。
javax.faces.application.ViewExpiredException: viewId:/index.xhtml - View /index.xhtml could not be restored.
at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:212)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:110)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at filter.HttpHttpsFilter.doFilter(HttpHttpsFilter.java:66)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:277)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
at java.lang.Thread.run(Thread.java:619)
解決方法は?
はじめに
その
ViewExpiredException
が投げられるたびに
javax.faces.STATE_SAVING_METHOD
に設定されます。
server
(デフォルト) で、エンドユーザーがビューに HTTP POST リクエストを送信する際に
<h:form>
と
<h:commandLink>
,
<h:commandButton>
または
<f:ajax>
のように、関連するビューの状態がセッションで利用できなくなったときに、そのビューの状態を変更することができます。
ビューの状態は、隠された入力フィールドの値として識別されます。
javax.faces.ViewState
の
<h:form>
. 状態の保存方法を
server
これは、セッション内のシリアライズされたビューステートを参照するビューステートIDのみを含んでいます。そのため、セッションが期限切れになったり、以下のような理由で不在になった場合、 ...
- セッションオブジェクトがサーバーでタイムアウトした
- クライアントでセッション Cookie がタイムアウトした
- クライアントでセッションクッキーが削除された
-
HttpSession#invalidate()
がサーバーで呼び出される -
SameSite=None
がセッション・クッキーで欠落している(したがって、例えば クローム は、サードパーティサイト(例:支払い)がコールバックURL経由であなたのサイトに戻るとき、それらを一緒に送信しません)
...その場合、シリアライズされたビューの状態はセッションで利用できなくなり、エンドユーザーはこの例外を受け取ります。セッションの動作を理解するために、次の項目も参照してください。 サーブレットはどのように動作するのですか?インスタンス化、セッション、共有変数、マルチスレッド .
また、JSFがセッションに保存するビューの量には制限があります。制限に達すると、最も最近に使用されたビューが期限切れになります。以下も参照してください。 com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews .
状態保存方法を
client
を指定すると、その
javax.faces.ViewState
非表示の入力フィールドには、代わりにシリアライズされたビューの状態全体が含まれるため、エンドユーザーは
ViewExpiredException
を使用すると、セッションが終了したときに しかし、クラスタ環境ではまだ起こる可能性があり ("ERROR: MAC did not verify" がその症状)、クライアント側の状態に実装特有のタイムアウトがある場合、サーバが再起動時にAESキーを再 生成する場合、などがあります。
クラスタ環境で状態保存方式がクライアントに設定され、ユーザーセッションが有効なときにViewExpiredExceptionを取得する。
解決方法
解決方法に関わらず、以下のことを確認してください。
ない
使用
enableRestoreView11Compatibility
.これは、元のビューの状態を復元することは一切ありません。これは基本的に、ビューと関連するすべてのビュースコープされたビーンをゼロから再作成するため、元のデータ (状態) をすべて失うことになります。アプリケーションは混乱した方法で動作するため ("Hey, where are my input values...?") 、これはユーザーエクスペリエンスにとって非常に悪いことです。ステートレス・ビューを使うか
<o:enableRestorableView>
そうすれば、すべてのビューで管理する代わりに、特定のビューだけで管理することができます。
については なぜ JSFはビューの状態を保存する必要があるため、この回答へどうぞ。 なぜJSFは、UIコンポーネントの状態をサーバーに保存するのですか?
ページ移動時のViewExpiredExceptionの回避
を回避するために
ViewExpiredException
に設定されている場合に、ログアウト後にナビゲートして戻る場合など。
server
ログアウト後のPOSTリクエストのリダイレクトだけでは不十分です。また、ブラウザに次のように指示する必要があります。
ではない
そうでなければ、ブラウザは、あなたがそれに対してGETリクエストを送るとき、サーバから新しいものを要求する代わりに、キャッシュからそれらを表示するかもしれません(例えば、バックボタンによって)。
は
javax.faces.ViewState
キャッシュされたページの hidden フィールドには、現在のセッションではもう有効でないビュー状態 ID 値が含まれている可能性があります。もし、ページ間のナビゲーションに GET (通常のリンク/ボタン) ではなく POST (コマンドリンク/ボタン) を (ab) 使用していて、キャッシュされたページでそのようなコマンドリンク/ボタンをクリックすると、今度は
ViewExpiredException
.
JSF 2.0でログアウト後にリダイレクトを発生させるには、以下のどちらかを追加します。
<redirect />
を
<navigation-case>
を追加するか、あるいは
?faces-redirect=true
を
outcome
の値を指定します。
<h:commandButton value="Logout" action="logout?faces-redirect=true" />
または
public String logout() {
// ...
return "index?faces-redirect=true";
}
ダイナミックJSFのページをキャッシュしないようにブラウザに指示するために
Filter
のサーブレット名にマッピングされます。
FacesServlet
を作成し、ブラウザのキャッシュを無効にするために必要なレスポンスヘッダを追加します。例
@WebFilter(servletNames={"Faces Servlet"}) // Must match <servlet-name> of your FacesServlet.
public class NoCacheFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
res.setDateHeader("Expires", 0); // Proxies.
}
chain.doFilter(request, response);
}
// ...
}
ページ更新時のViewExpiredExceptionの回避
を回避するために
ViewExpiredException
に設定されている場合、現在のページを更新するときに、状態保存が
server
の場合、ページ間のナビゲーションをGETのみで行っていることを確認するだけでなく(通常のリンク/ボタン)、フォームの送信にajaxのみを使用していることを確認する必要があります。もしフォームを同期的に(非ajaxで)送信するなら、ビューをステートレスにするか(後のセクションを参照)、POSTの後にリダイレクトを送信する(前のセクションを参照)ことが最善です。
を持つことで
ViewExpiredException
は、デフォルトでは非常にまれなケースです。これは、JSFがセッションに保存するビューの量の限界に達したときにのみ発生する可能性があります。つまり、手動で制限値を低く設定しすぎた場合や、継続的に新しいビューをバックグラウンドで作成している場合(例えば、同じページで適切に実装されたajax pollや、同じページで壊れた画像に対して適切に実装された404エラーページ)にのみ発生することになります。以下も参照してください。
com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews
を参照してください。もう一つの原因は、ランタイムクラスパスに重複したJSFライブラリがあり、互いに競合していることです。JSFをインストールするための正しい手順については、以下を参照してください。
JSF wikiページ
.
ViewExpiredExceptionの処理
やむを得ず
ViewExpiredException
ログアウトしているときに、あるブラウザのタブ/ウィンドウで既に開かれている任意のページに対する POST アクションの後に、別のタブ/ウィンドウでログアウトしているときに
error-page
の中で、そのための
web.xml
というページが表示されます。例
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/WEB-INF/errorpages/expired.xhtml</location>
</error-page>
エラーページのメタリフレッシュヘッダを使用する場合は、必要に応じて、実際に リダイレクト をホームまたはログインページに移動させます。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Session expired</title>
<meta http-equiv="refresh" content="0;url=#{request.contextPath}/login.xhtml" />
</head>
<body>
<h1>Session expired</h1>
<h3>You will be redirected to login page</h3>
<p><a href="#{request.contextPath}/login.xhtml">Click here if redirect didn't work or when you're impatient</a>.</p>
</body>
</html>
(その
0
で
content
はリダイレクトまでの秒数を表します。
0
ということは、「すぐにリダイレクトする」という意味です。
3
を指定すると、ブラウザはリダイレクトを行うまで3秒間待機します)
ajaxリクエスト時の例外処理には、特別な
ExceptionHandler
. 参照
JSF/PrimeFacesのajaxリクエストにおけるセッションタイムアウトとViewExpiredExceptionの処理について
. 次のサイトでライブの例を見ることができます。
オムニフェース
FullAjaxExceptionHandler
ショーケースページ
(これは、非ajaxリクエストもカバーします)。
また、一般的なエラーページのマッピングは
<error-code>
の
500
の代わりに
<exception-type>
の、例えば
java.lang.Exception
または
java.lang.Throwable
でラップされたすべての例外は
ServletException
のように
ViewExpiredException
を実行しても、一般的なエラーページで終わってしまいます。以下も参照してください。
web.xml の java.lang.Throwable エラーページで表示される ViewExpiredException
.
<error-page>
<error-code>500</error-code>
<location>/WEB-INF/errorpages/general.xhtml</location>
</error-page>
ステートレスビュー
完全に異なる選択肢は、JSFのビューをステートレスモードで実行することです。この方法では、JSFの状態は何も保存されず、ビューは決して期限切れにならず、ただリクエストごとにゼロから再構築されます。ステートレスビューは
transient
属性の
<f:view>
から
true
:
<f:view transient="true">
</f:view>
このように
javax.faces.ViewState
という固定値を取得します。
"stateless"
をMojarraに追加しました(現時点ではMyFacesは未確認)。なお、この機能は
導入
は、Mojarra 2.1.19 および 2.2.0 に収録されており、それ以前のバージョンでは使用できません。
その結果、ビューをスコープとしたビーンは使用できなくなりました。リクエストスコープドビーンズと同じように動作するようになります。欠点は、隠し入力や緩いリクエストパラメータを操作することで、 状態を自分で追跡しなければならないことです。主に、入力フィールドを持つフォームで
rendered
,
readonly
または
disabled
属性で、ajaxイベントによって制御されるものは影響を受けます。
ただし
<f:view>
は必ずしもビュー全体で一意である必要はなく、マスターテンプレートにのみ存在してもかまいません。また、テンプレートクライアントの中で再宣言し、ネストすることは全く合法的です。これは基本的に、親テンプレートの
<f:view>
であれば 例:マスターテンプレートで
<f:view contentType="text/html">
<ui:insert name="content" />
</f:view>
で、テンプレートクライアントでは
<ui:define name="content">
<f:view transient="true">
<h:form>...</h:form>
</f:view>
</f:view>
をラップすることもできます。
<f:view>
の中に
<c:if>
を使って条件付きにすることができます。なお、これは
全体
ビューだけでなく、ネストされたコンテンツ、たとえば
<h:form>
のようになります。
こちらもご覧ください
- web.xml の java.lang.Throwable のエラーページで表示される ViewExpiredException
- セッションが存在するかどうかをチェックする JSF
- JSF/PrimeFacesのajaxリクエストにおけるセッションタイムアウトとViewExpiredExceptionの処理について
関連性のないもの
は具体的な問題ですが、純粋なページ間ナビゲーションにHTTP POSTを使用することは、ユーザーやSEOにとってあまり好ましいことではありません。JSF 2.0では、本当に
<h:link>
または
<h:button>
の上に
<h:commandXxx>
は、ページ間のナビゲーションのためのものです。
そのため、例えばの代わりに
<h:form id="menu">
<h:commandLink value="Foo" action="foo?faces-redirect=true" />
<h:commandLink value="Bar" action="bar?faces-redirect=true" />
<h:commandLink value="Baz" action="baz?faces-redirect=true" />
</h:form>
ベタード
<h:link value="Foo" outcome="foo" />
<h:link value="Bar" outcome="bar" />
<h:link value="Baz" outcome="baz" />
こちらもご覧ください
関連
-
[解決済み] javax.faces.application.ViewExpiredException: ビューを復元できませんでした
-
[解決済み] <f:facet>は何をするもので、どのような場合に使用するのですか?
-
[解決済み] JSF 2.2でターゲットが到達できない、識別子がヌルに解決される [重複] 。
-
[解決済み] java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.Config [duplicate].
-
[解決済み] javax.validation.ConstraintViolationException
-
[解決済み] commandButton/commandLink/ajax アクション/リスナーメソッドが呼び出されないか、入力値が設定/更新されない。
-
[解決済み] <f:metadata>、<f:viewParam>、<f:viewAction>は何に使えるのでしょうか?
-
[解決済み] javax.el.PropertyNotFoundException の識別と解決。ターゲットに到達できない
-
[解決済み] divタグをレンダリングできるjsfコンポーネントは何ですか?
-
[解決済み] h:commandLinkの代わりにh:outputLinkを使うべきですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] JSF 2.2でターゲットが到達できない、識別子がヌルに解決される [重複] 。
-
[解決済み] java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.Config [duplicate].
-
[解決済み] javax.validation.ConstraintViolationException
-
[解決済み] p:dashboardが終了してもソート順を維持する。
-
[解決済み] actionとactionListenerの違い
-
[解決済み】JSFリソースライブラリは何のためにあり、どのように使用すべきですか?
-
[解決済み】PrimeFacesのprocess/updateとJSFのf:ajax execute/renderの属性を理解する。
-
[解決済み] JSF2 FaceletsでJSTL...意味があるのか?
-
[解決済み] javax.el.PropertyNotFoundException の識別と解決。ターゲットに到達できない
-
[解決済み] divタグをレンダリングできるjsfコンポーネントは何ですか?