java JSF 需要的 URL 重写解决方案

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9905946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 22:49:37  来源:igfitidea点击:

URL rewriting solution needed for JSF

javajsfweb-applicationsjsf-2prettyfaces

提问by andbi

Suppose the following application landscape:

假设以下应用场景:

+-----------------+
| App server      |
+-----------------+
|                 |                                   +-------+
| ear1            |                                   |       |
|  +-web1 (/ctx1) +--<-- http://localhost/ctx1/xxx/ --+       +--<-- http://www.example.com/xxx/
|                 |                                   |       |
|                 |                                   | proxy |
| ear2            |                                   |       |
|  +-web2 (/ctx2) +--<-- http://localhost/ctx2/yyy/ --+       +--<-- http://abc.example.com/yyy/
|                 |                                   |       |
+-----------------+                                   +-------+

As you can see, proxy (nginxin my case) is forwarding requests to to a single application server instance, which in turn has multiple web modules with different context paths. Of course I dont want my public server to expose internal context roots and proxy does it's job well, wraps and unwraps http requests, etc. But there is still one big problem: JSF-generated html code (links, css, js resources, form actions) contains context paths, /ctx1and /ctx2in my case. That's what I want to avoid.

如您所见,代理(nginx就我而言)将请求转发到单个应用程序服务器实例,该实例又具有多个具有不同上下文路径的 Web 模块。当然我不希望我的公共服务器暴露内部上下文根和代理它的工作做得很好,包装和解包 http 请求等。但仍然有一个大问题:JSF 生成的 html 代码(链接、css、js 资源、表单动作)包含上下文路径,/ctx1/ctx2在我的情况。这就是我想要避免的。

I nave no solution at this moment of time except of using more and more different instances (domains) of application server, causing my hardware resources to fade away. As i understand it, I need to extend my JSF applications with some wrappers, potentially registered in faces-config.xml, which would remove context prefix in generated html. Any other solutions are also welcome.

我此时除了使用越来越多不同的应用服务器实例(域),导致我的硬件资源逐渐消失之外,没有任何解决方案。据我了解,我需要使用一些包装器来扩展我的 JSF 应用程序,这些包装器可能在 中注册faces-config.xml,这将删除生成的 html 中的上下文前缀。也欢迎任何其他解决方案。

Please point me in the right direction.

请指出我正确的方向。

采纳答案by andbi

I'm posting solution which may be helpful for others facing the same problem. All I needed to do is implementing my own javax.faces.application.ViewHandlerand register it in faces-config.xml:

我正在发布可能对面临同样问题的其他人有所帮助的解决方案。我需要做的就是实现我自己的javax.faces.application.ViewHandler并将其注册到faces-config.xml

public class CustomViewHandler extends ViewHandlerWrapper {
  private ViewHandler wrappped;

  public CustomViewHandler(ViewHandler wrappped) {
    super();
    this.wrappped = wrappped;
  }

  @Override
  public ViewHandler getWrapped() {
    return wrappped;
  }

  @Override
  public String getActionURL(FacesContext context, String viewId) {
    String url =  super.getActionURL(context, viewId);
    return removeContextPath(context, url);
  }

  @Override
  public String getRedirectURL(FacesContext context, String viewId, Map<String, List<String>> parameters, boolean includeViewParams) {
    String url =  super.getRedirectURL(context, viewId, parameters, includeViewParams);
    return removeContextPath(context, url);
  }

  @Override
  public String getResourceURL(FacesContext context, String path) {
    String url = super.getResourceURL(context, path);
    return removeContextPath(context, url);
  }

  private String removeContextPath(FacesContext context, String url) {
    ServletContext servletContext = (ServletContext) context.getExternalContext().getContext();
    String contextPath = servletContext.getContextPath();
    if("".equals(contextPath)) return url; // root context path, nothing to remove
    return url.startsWith(contextPath) ? url.substring(contextPath.length()) : url;
  }
}

faces-config.xml :

面孔-config.xml :

<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
              version="2.0">
  <application>
    <view-handler>test.CustomViewHandler</view-handler>
  </application>
</faces-config>

回答by Lincoln

You can use OCPsoft Rewrite URLRewriteFilterfor this (not PrettyFaces currently, but you can use them both at the same time until they formally join together after PrettyFaces 4 release - Rewrite is the core project for PrettyFaces 4)

您可以为此使用OCPsoft Rewrite URLRewriteFilter(目前不是 PrettyFaces,但您可以同时使用它们,直到它们在 PrettyFaces 4 发布后正式连接在一起 - Rewrite 是 PrettyFaces 4 的核心项目)

Doing something like this should be fairly straightforward using a single configuration rule. You can obviously fiddle if this rule is either too strict or too general.

使用单个配置规则执行此类操作应该相当简单。如果这条规则太严格或太笼统,你显然可以摆弄。

.defineRule()
.when(URL.matches("{prefix}" + context.getContextPath() + "{suffix}")
.perform(Substitute.with("{prefix}{suffix}"))

Check out the rewrite site. It's pretty easy to set up. http://ocpsoft.org/rewrite/

查看重写站点。设置起来很容易。http://ocpsoft.org/rewrite/

回答by Toastor

I was facing the same problem and tried your solution. While it was more or less working, there were still a few glitches. And to be honest, it feels more like fighting the symptoms as opposed to curing the illness.

我遇到了同样的问题并尝试了您的解决方案。虽然它或多或少地工作,但仍有一些小故障。老实说,感觉更像是对抗症状而不是治愈疾病。

So here's what finally worked for me:

所以这就是最终对我有用的东西:

Instead of setting the deployments apart through the path, I assigned each deployment to its own port:

我没有通过路径将部署分开,而是将每个部署分配到自己的端口:

foo.war <-- http://localhost:8080/ -- | Proxy | <-- http://www.foo.com -- | Client |
bar.war <-- http://localhost:8181/ -- | Proxy | <-- http://www.bar.com -- | Client |

This way, both deployments are able to use / as their context path, hence no need to edit the context path out.

这样,两个部署都可以使用 / 作为它们的上下文路径,因此无需编辑上下文路径。

To achieve this, you don't necessarily have to run two application servers. In my case (Wildfly 10.0) it was sufficient to define two undertow servers in the wildfly configuration, each with its own virtual host and http listener, like so:

要实现这一点,您不必运行两个应用程序服务器。在我的情况下(Wildfly 10.0),在 Wildfly 配置中定义两个 undertow 服务器就足够了,每个服务器都有自己的虚拟主机和 http 侦听器,如下所示:

<server name="foo-server">
   <http-listener name="foo-listener" proxy-address-forwarding="true" socket-binding="foo-http"/>
   <host name="foo-host" default-web-module="foo.war" alias="localhost, foo.com, wwww.foo.com"/>
</server>
<server name="bar-server">
   <http-listener name="bar-listener" proxy-address-forwarding="true" socket-binding="bar-http"/>
   <host name="bar-host" default-web-module="bar.war" alias="localhost, bar.com, wwww.bar.com"/>
</server>

<socket-binding name="foo-http" port="${jboss.http.port:8080}"/>
<socket-binding name="bar-http" port="${jboss.http.port:8181}"/>

You will also need a jboss-web.xml in your project:

您的项目中还需要一个 jboss-web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
   <server-instance>foo-server</server-instance>
   <virtual-host>foo-host</virtual-host>
   <context-root>/</context-root>
</jboss-web>

The two servers are needed because you can't add a socket binding to a virtual host. So there is a slight overhead here, but negligible compared to running two complete application servers.

需要两台服务器,因为您无法将套接字绑定添加到虚拟主机。所以这里的开销很小,但与运行两个完整的应用程序服务器相比可以忽略不计。

Edit 1:

编辑1:

It just occured to me that it is probably not even necessary to use different ports and using one undertow server per deplyoment is probably superfluous as well.

我突然想到,甚至可能没有必要使用不同的端口,并且每个部署使用一个 undertow 服务器也可能是多余的。

Since the proxy is able to forward the host as requested by the client to the application server, undertow should be able to pick out the proper virtual host via the alias parameter.

由于代理能够将客户端请求的主机转发到应用服务器,undertow 应该能够通过别名参数挑选出合适的虚拟主机。

So basically, the proxy would relay any request to either foo.com or bar.com to localhost:8080 and let the AS sort things out.

所以基本上,代理会将任何请求转发到 foo.com 或 bar.com 到 localhost:8080 并让 AS 解决问题。

I have not tested this, but here's how it could work (again, this is for Wildfly 10.0):

我还没有测试过这个,但它是如何工作的(同样,这适用于 Wildfly 10.0):

<server name="default-server">
   <http-listener name="http" proxy-address-forwarding="true" socket-binding="http"/>
   <host name="foo-host" default-web-module="foo.war" alias="foo.com, wwww.foo.com"/>
   <host name="bar-host" default-web-module="bar.war" alias="bar.com, wwww.bar.com"/>
</server>

And the jboss-web.xml would loose the server tag:

jboss-web.xml 会丢失服务器标签:

<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
   <virtual-host>foo-host</virtual-host>
   <context-root>/</context-root>
</jboss-web>

In case this works there would be no overhead involved at all.

如果这有效,则根本不会涉及任何开销。

Edit 2:

编辑2:

Just tested the simplified approach - yep, it works :)

刚刚测试了简化的方法 - 是的,它有效:)