序章
通常、JSF / Faceletsは、ビューの作成/復元時に、要求パラメーターの文字エンコードをデフォルトでUTF-8に設定します。ただし、ビューが作成/復元される前に要求パラメーターが要求された場合、適切な文字エンコードを設定するには遅すぎます。つまり、リクエストパラメータは1回だけ解析されます。
PrimeFacesエンコーディングが失敗する
2.xからのアップグレード後にPrimeFaces3.xで失敗したのは、要求パラメーターをチェックするisAjaxRequest()
PrimeFacesの新しいオーバーライドが原因です。PrimePartialViewContext
@Override
public boolean isAjaxRequest() {
return getWrapped().isAjaxRequest()
|| FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().containsKey("javax.faces.partial.ajax");
}
デフォルトでは、isAjaxRequest()
(上記のPrimeFacesコードによって取得されたMojarra / MyFacesの1つgetWrapped()
)は、要求ヘッダーが取得されたときに要求パラメーターが解析されないため、要求パラメーターのエンコードに影響を与えない次のように要求ヘッダーをチェックします。
if (ajaxRequest == null) {
ajaxRequest = "partial/ajax".equals(ctx.
getExternalContext().getRequestHeaderMap().get("Faces-Request"));
}
ただし、ビューが作成/復元される前にisAjaxRequest()
、任意のフェーズリスナー、システムイベントリスナー、または一部のアプリケーションファクトリによって呼び出される場合があります。したがって、PrimeFaces 3.xを使用している場合、適切な文字エンコードが設定される前に要求パラメーターが解析されるため、サーバーのデフォルトのエンコード(通常はISO-8859-1)が使用されます。これはすべてを台無しにします。
ソリューション
それを修正するいくつかの方法があります:
UTF-8で設定するサーブレットフィルタを使用します。ちなみに、この問題の影響を受けないためServletRequest#setCharacterEncoding()
、応答エンコーディングの設定は不要です。ServletResponse#setCharacterEncoding()
@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
// ...
}
HttpServletRequest#setCharacterEncoding()
GETリクエストパラメータではなく、POSTリクエストパラメータのエンコーディングのみを設定することを考慮する必要があります。GETリクエストパラメータの場合は、サーバーレベルで設定する必要があります。
JSFユーティリティライブラリOmniFacesを使用する場合、そのようなフィルタはすでにボックスから提供されていますCharacterEncodingFilter
。web.xml
最初のフィルターエントリとして、以下のようにインストールするだけです。
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.omnifaces.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
デフォルトのエンコーディングとしてISO-8859-1の代わりにUTF-8を使用するようにサーバーを再構成します。Glassfishの場合は<glassfish-web-app>
、/WEB-INF/glassfish-web.xml
ファイルに次のエントリを追加する必要があります。
<parameter-encoding default-charset="UTF-8" />
Tomcatはそれをサポートしていません。URIEncoding
エントリに属性があります<Context>
が、これはGETリクエストにのみ適用され、POSTリクエストには適用されません。
バグとしてPrimeFacesに報告してください。標準のJSFやjQueryの場合のように、リクエストヘッダーではなくリクエストパラメータをチェックすることで、HTTPリクエストがajaxリクエストであることを確認する正当な理由は本当にありますか?PrimeFacesのcore.js
JavaScriptがそれを行っています。のリクエストヘッダーとして設定した方が良いでしょうXMLHttpRequest
。
動作しないソリューション
おそらく、この問題を調査しているときに、インターネット上のどこかで「解決策」の下に出くわすでしょう。これらのソリューションは、この特定のケースでは機能しません。説明は次のとおりです。
XMLプロローグの設定:
<?xml version='1.0' encoding='UTF-8' ?>
これは、XMLパーサーにUTF-8を使用してXMLソースをデコードしてから、その周りにXMLツリーを構築するように指示するだけです。Faceltsによって実際に使用されているXMLパーサーは、JSFビューのビルド時にSAXです。この部分は、HTTP要求/応答エンコーディングとはまったく関係がありません。
HTMLメタタグの設定:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
http(s)://
ページがURIを介してHTTP経由で提供される場合、HTMLメタタグは無視されます。file://
これは、ページがクライアントによってローカルディスクシステムにHTMLファイルとして保存され、ブラウザのURIによって再度開かれた場合にのみ使用されます。
HTMLフォームの設定はcharset属性を受け入れます:
<h:form accept-charset="UTF-8">
最近のブラウザはこれを無視します。これは、MicrosoftInternetExplorerブラウザでのみ効果があります。それでも、それは間違ってやっています。絶対に使用しないでください。Content-Type
すべての実際のWebブラウザーは、代わりに応答のヘッダーで指定されたcharset属性を使用します。accept-charset
属性を指定しない限り、MSIEでも正しい方法で実行されます。
JVM引数の設定:
-Dfile.encoding=UTF-8
これは、Javaソースファイルを読み取って解析するためにOracle(!)JVMによってのみ使用されます。