2

Background

JBoss 7.1.5 EAP back-end with an Angular 7 UI.

I need to make JBoss aware of the UI's routes, but rewrite them all to the UI's index page for routing by Angular.

The project is structured thus:

webapp/
  WEB-INF/
    undertow-handlers.conf
    web.xml
    ...etc
  login/
    background.jpg
  login.jsp
  index.jsp

  assets/*
  ...html
  ...js
  ...css

index.jsp simply response.sendRedirect("index.html")s, where index.html is part of the assets produced by the Angular CLI. JavaScript and HTML is served from webapp/, images from webapp/assets/.

Configuration

From standalone-full.xml

<subsystem xmlns="urn:jboss:domain:undertow:4.0">
    <buffer-cache name="default"/>
    <server name="default-server">
        <http-listener name="http" socket-binding="http" redirect-socket="https"/>
        <host name="default-host" alias="localhost,workstation">
            <location name="/" handler="welcome-content"/>
            <filter-ref name="request-dumper"/>
        </host>
    </server>
    <servlet-container name="default">
        <jsp-config x-powered-by="false"/>
        <websockets/>
    </servlet-container>
    <handlers>
        <file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
    </handlers>
    <filters>
        <filter name="request-dumper" module="io.undertow.core" class-name="io.undertow.server.handlers.RequestDumpingHandler"/>
    </filters>
</subsystem>

and

<subsystem xmlns="urn:jboss:domain:web:2.2" default-virtual-server="default-host" native="false">
    <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http"/>
    <virtual-server name="default-host">
        <alias name="localhost"/>
        <alias name="workstation"/>
    </virtual-server>
</subsystem>

With the above configuration, I see the expected server log:

[org.wildfly.extension.undertow] (ServerService Thread Pool -- 84) WFLYUT0021: Registered web context: '/' for server 'default-server'

And I can access the site's login page, and the URI / serves the main angular index page and assets as expected.

Problem

What I need is for paths in this context (like /base or /shop/60) to be handled by Angular, so redirected to index.

As a simple test based on this answer, I have tried this single rule in WEB-INF/undertow-handlers.conf:

exists(%{RELATIVE_PATH}) -> done
path-prefix('/') -> rewrite('/');

but it seems to do nothing at all as I get a 404.

I've tried -> rewrite('/index.html') and -> rewrite('/index.jsp') to no avail.

The file is clearly being read, though, because if I put garbage into the file it throws an exception in the server log.

UT000045: Error parsing predicated handler string Invalid expression:
# path('/base') -> rewrite('/')

What have I missed?

I'm quite a neophyte to JBoss and the whole Undertow ecosystem; please let me know what other details I should add to this question.

Curiosity

With request dumper activated, I see a single initial request to / made by JBoss (User-Agent=Java/1.8.0_181) immediately after booting, but when I navigate to / from a browser, I don't see that request in the dump. But I do see the failed request for /base. Why is that?

msanford
  • 11,803
  • 11
  • 66
  • 93

2 Answers2

5

I'm serving an Angular 8 SPA from /gui (like you my API is in another servlet). All I had to do with Undertow 2.0.15 (EAP 7.2) was add a WEB-INF/undertow-handlers.conf with:

path-prefix['gui'] and not file(%U) -> rewrite('/gui/index.html')

I would guess that if your SPA is served at / you could just:

not file(%U) -> rewrite('/index.html')
HoleStein
  • 66
  • 1
  • 2
  • Cool! I didn't know this was available. We've since restructured the site to use nginx in Docker, but this is far more elegant so have my checkmark. – msanford Jun 18 '20 at 12:52
3

I had two problems:

I was missing rules, and I has misunderstood the function of path-prefix (which matches on complete and non-terminal path segments, rather than acting like a regex ^(group)).

My final, working undertow-handlers.conf looks like this:

regex('/login(.*)') -> done;

path-prefix('/assets') -> done;

regex('(.*).js') -> done;
regex('(.*).map') -> done;

regex('(.*).svg') -> done;
regex('(.*).png') -> done;

regex('(.*).eot') -> done;
regex('(.*).woff2') -> done;

regex('(.*).html') -> done;

path('/') -> rewrite('/index.html');

path('/base') -> rewrite('index.html');
path-prefix('/shop') -> rewrite('index.html');


...and all my other angular routes

Note that /base is a terminal path segment, and matches with path, whereas /shop/60 takes an additional path parameter, so requires path-prefex.

For whatever reason, the solution proposed in the linked question above, simply capturing it all with path-prefix('/') didn't work in my case.

Possibly-heplful side-note: we have a REST server that serves from /RestService/ in another servlet context, so no rules were needed to allow that to continue to work.

Additionally, I was using webpack's development proxy server through ng hmr, and needed to add byPassProxy rules equivalent to the undertow rules, as well.

I'm happy for improvements on this: please don't hesitate to comment or add another answer.

msanford
  • 11,803
  • 11
  • 66
  • 93