2012-03-28 5 views
7

Angenommen, die folgende Anwendungslandschaft:JSF. URL-Rewriting Lösung benötigte

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

Wie Sie sehen können, Proxy (nginx in meinem Fall) Anfragen an auf eine einzige Anwendungsserverinstanz weiterzuleiten, die wiederum mehrere Web-Module hat mit verschiedene Kontextpfade Natürlich möchte ich nicht, dass mein öffentlicher Server interne Kontextrohts aufdeckt und Proxy tut es gut, wickelt und entpackt HTTP-Anfragen, etc. Aber es gibt noch ein großes Problem: JSF-generierten HTML-Code (Links, CSS, JS-Ressourcen, Formular Aktionen) enthält Kontextpfade, /ctx1 und /ctx2 in meinem Fall. Das möchte ich vermeiden.

Ich habe keine Lösung in diesem Moment der Zeit außer der Verwendung mehr und mehr Instanzen (Domänen) des Anwendungsservers, wodurch meine Hardware-Ressourcen verblassen. Wie ich es verstehe, muss ich meine JSF-Anwendungen mit einigen Wrappern erweitern, die möglicherweise in faces-config.xml registriert sind, was das Kontextpräfix in generiertem HTML entfernen würde. Andere Lösungen sind ebenfalls willkommen.

Bitte zeigen Sie mir in die richtige Richtung.

Antwort

4

Ich poste Lösung, die für andere mit dem gleichen Problem hilfreich sein kann. Alles, was ich meine eigene javax.faces.application.ViewHandler und registrieren Sie es in faces-config.xml tun musste, ist die Umsetzung:

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:

<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> 
+2

Hinweis: Dies kann auch mit einem 'Filter' und weniger als die Hälfte des Codes durchgeführt werden. – BalusC

+0

@BalusC, heute war ich im Begriff, Ihre Filter-Lösung zu implementieren, war aber erschrocken durch die Tatsache, dass Ihr Beitrag gelöscht wurde)) – Osw

+0

Ich löschte es nur, weil es den Aufwand schließlich nicht wert war. – BalusC

5

Sie können für diese PrettyFaces zur Zeit, aber man kann (nicht verwenden OCPsoft Rewrite URLRewriteFilter benutze sie beide gleichzeitig, bis sie nach der Veröffentlichung von PrettyFaces 4 formell miteinander verbunden sind - Rewrite ist das Kernprojekt von PrettyFaces 4)

So etwas sollte mit einer Sünde ziemlich einfach sein Konfigurationsregel. Sie können offensichtlich fiedeln, wenn diese Regel entweder zu streng oder zu allgemein ist.

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

Überprüfen Sie die Website neu schreiben. Es ist ziemlich einfach einzurichten. http://ocpsoft.org/rewrite/

+0

Hallo Lincoln! Wird es auch für css, js und andere Ressourcen funktionieren, die ich auf meinen Seiten habe? – Osw

+0

Solange diese Links über JSF gerendert werden und im HTML nicht fest codiert sind, dann ja, absolut. Andernfalls können Sie zusätzliche Regeln zur Behandlung dieses Szenarios einrichten. – Lincoln

1

Ich hatte das gleiche Problem und versuchte Ihre Lösung. Während es mehr oder weniger funktionierte, gab es immer noch ein paar Pannen. Und um ehrlich zu sein, fühlt es sich eher an, die Symptome zu bekämpfen als gegen die Krankheit zu heilen.

Also hier ist was für mich endlich geklappt:

Statt die Einsätze außer durch den Weg der Einstellung, ich jeden Einsatz der eigenen Port zugeordnet:

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

diese Weise beide Einsätze sind in der Lage Verwenden Sie/als ihren Kontextpfad, daher müssen Sie den Kontextpfad nicht bearbeiten.

Um dies zu erreichen, müssen Sie nicht unbedingt zwei Anwendungsserver ausführen. In meinem Fall (Wildfly 10,0) war es ausreichend, zwei undertow Server in der Wildfly Konfiguration zu definieren, die jeweils mit einem eigenen virtuellem Host und HTTP-Listener, etwa so:

<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}"/> 

Sie werden auch ein Jboss-Web benötigen.xml in Ihrem Projekt:

<?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> 

Die zwei Server werden benötigt, da Sie keine Socket-Bindung zu einem virtuellen Host hinzufügen können. Es gibt also einen kleinen Overhead, der aber vernachlässigbar ist, verglichen mit dem Ausführen von zwei vollständigen Anwendungsservern.

Edit 1:

Es fiel mir nur, dass es wahrscheinlich nicht einmal notwendig ist, verschiedene Ports zu verwenden und mit einem undertow Server pro deplyoment ist wahrscheinlich auch überflüssig.

Da der Proxy den Host, wie vom Client angefordert, an den Anwendungsserver weiterleiten kann, sollte undertow in der Lage sein, den richtigen virtuellen Host über den Alias-Parameter auszuwählen.

Im Grunde würde der Proxy jede Anfrage an foo.com oder bar.com an localhost: 8080 weiterleiten und die AS die Dinge sortieren lassen.

ich diese nicht getestet haben, aber hier ist, wie es funktionieren kann (auch dies ist für 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> 

Und der Jboss-web.xml würde den Server-Tag verlieren:

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

Falls dies funktioniert, würde es überhaupt keinen Aufwand geben.

Edit 2:

getestet einfach die vereinfachten Ansatz - yep, es funktioniert :)