tamuraです。
ローカルで開発しているときは問題なかったのに、 本番環境は reverse proxy を使っているので、 JSFが生成するURLが違ってしまう場合がある、ということがあります。
例
/xxxx/app に来たアクセスを Tomcat の /app に横流しする
<Location /xxxx/app/>
ProxyPass ajp://localhost:8009/app/
ProxyPassReverse ajp://localhost:8009/app/
ProxyPassReverseCookiePath /app/ /xxxx/app/
</Location>
このとき、このようなJSFがあった場合
JSFに書かれた内容
<h:form>
<ul>
<li>
<h:commandLink action="#{test.init}" ajax="false" immediate="true">
test
</h:commandLink>
</ul>
</h:form>
通常であればこのようなHTMLが生成されます。
<form id="xxxx" nam="xxxx" method="post" action="/app/index.xhtml" enctype="application/x-www-form-urlencoded">
<!-- 省略 -->
<ul>
<li>
<script type="text/javascript" src="/app/ajax.faces.resource/jsf.js.xhtml?lnjavax.faces"></script>
<a href="#" onclick="xxxxxxxx">
test
</a>
</li>
</ul>
</form>
でも実際に生成してほしいHTMLはこのような形になります。
<form id="xxxx" nam="xxxx" method="post" action="/operation/app/index.xhtml" enctype="application/x-www-form-urlencoded">
<!-- 省略 -->
<ul>
<li>
<script type="text/javascript" src="/operation/app/ajax.faces.resource/jsf.js.xhtml?lnjavax.faces"></script>
<a href="#" onclick="xxxxxxxx">
test
</a>
</li>
</ul>
</form>
ViewHandler で対応する
ViweHandler
を使って、URLを生成しているタイミングで proxy 用のパスを追加します。
(ViewHandler
すべてを実装するのは面倒なので、ViewHandlerWrapper
を使っています)
public class ReverseProxyViewHandler extends ViewHandlerWrapper {
protected ViewHandler defaultHandler;
public ReverseProxyViewHandler(ViewHandler defaultHandler) {
super();
this.defaultHandler = defaultHandler;
}
@Override
public ViewHandler getWrapped() {
return this.defaultHandler;
}
@Override
public String getActionURL(FacesContext context, String viewId) {
String actionURL = defaultHandler.getActionURL(context, viewId);
String proxyPath = getProxyPath(context);
return genURL(proxyPath, actionURL);
}
@Override
public String getResourceURL(FacesContext context, String viewId) {
String resourceURL = defaultHandler.getResourceURL(context, viewId);
String proxyPath = getProxyPath(context);
return genURL(proxyPath, resourceURL);
}
private String getProxyPath(FacesContext context) {
String proxyPath = context.getExternalContext().getInitParameter("PROXY_PATH");
if (proxyPath == null) {
return "";
}
else {
return proxyPath;
}
}
private String genURL(String proxyPath, String url) {
StringBuilder buf = new StringBuilder(proxyPath).append(url);
return buf.toString();
}
}
#getProxyPath(FacesContext)
で web.xml に設定した初期値を取得するようにしてます。
設定
web.xml に proxy 用のパスを設定します。
<!-- for Reverse Proxy -->
<context-param>
<param-name>PROXY_PATH</param-name>
<param-value>/xxxx</param-value>
</context-param>
faces-config.xml に ViewHandler
を指定します。
<!-- for Reverse Proxy -->
<application>
<view-handler>com.github.tamurashingo.jsfapp.ReverseProxyViewHandler</view-handler>
</application>
この内容で view を生成すると、 action や img のパスが proxy を考慮した形になります。