Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[jetty-users] Embedded Jetty and Angular 6: only rewrite URLs that don`t match any servlet or files

Hi,

I want to add an Angular 6 application to an existing embedded Jetty web server (version 9.4.12.v20180830). I am having a problem getting client-side page routing to work properly.

For example:
Is a valid Angular route, but does not exist as a file.
I can navigate to it either via a link on the home page  (index.html) or by typing: http://localhost:8080/#/mypage in my browser.

If I type http://localhost:8080/mypage,  I get a 404.

That is because for client-side routing feature to work properly, HTML 5 PushState must be supported. From my understanding, what this means is that the server must rewrite URLs so that they reach the angular page on /index.html. Using the above example, "/mypage" would have to be rewritten to "/index.html" with an original path attribute set to the requested path.

Here is are links to Angular documentation: 

I've been working at it for a few days and am stuck. I have found how to do url rewriting with Jetty, using a RewriteHandler. The rewriting works, but is affecting all URLs, including valid ones. This causes script files and images to be replaced with contents of index.html.

I need URLs associated with other servlets (such as websocket servlets and rest apis) to be left untouched, and I need URLs for real files (such as images and other angular assets) to be left untouched.

I have been looking for something in the like of Ngnx:
try_files $uri $uri/ /index.html; 

Which translates into "try the URI as-is, if that doesn`t work, treat the URI as a folder, if that doesnt work then use index.html"

So I tried this with Jetty:

// Create the web app context
WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setWelcomeFiles(new String[] {"index.html"});
String resLocation = WebServer.class.getResource("/webapp").toString();
context.setResourceBase(resLocation);

// Enable URL Rewriting to support HTML 5 PushState
RewriteHandler rewrite = new RewriteHandler();
rewrite.setRewriteRequestURI(true);
rewrite.setRewritePathInfo(false);
rewrite.setOriginalPathAttribute("requestedPath");

RewriteRegexRule html5pushState = new RewriteRegexRule();
html5pushState.setRegex("/.*");
html5pushState.setReplacement("/index.html");
rewrite.addRule(html5pushState);

// Handler Structure
HandlerList handlers = new HandlerList();
rewrite.setHandler(context);
handlers.setHandlers(new Handler[] { context, rewrite}); 
server.setHandler(handlers);


I was hoping this would do the trick. My rationale was that using a HandlerList would cause Jetty to call each handler in the list in the order specified until a response is matched.  Calling context first would lookup all the existing webapps for a file or servlet.  Then calling rewrite would rewrite the URL and then because context is also a child of rewrite I was hoping this would cause Jetty to try again using the rewritten URL, in which case would be index.html.

Unfortunately, It doesn`t work because "context" returns a 404 to the client directly. The rewrite handler is never called.


I've been looking for Conditional statements in Jetty and couldn`t find any. In fact, I was able to do this kind of conditional rewrite with Tomcat using a RewriteValve:
ctx.addValve(new RewriteValve());

and a text file (rewrite.config):

RewriteCond %{REQUEST_URI} -f
RewriteRule ^(.*)$ - [L]

RewriteRule ^(.*)$ /index.html


Notice how the rewrite rule is conditional.   The rewrite occurs only if the URL cannot be matched to a file.



How can this kind of conditional rewriting be done under Jetty?

If a custom handler must be written, how would you guys query the server to figure out if a given path matches a servlet or a file?

Your help would be very much appreciated.

Nicolas Therrien

Senior Software Developer

https://www.motorolasolutions.com/content/dam/msi/images/logos/corporate/msiemailsignature.png

o: +1.819.931.2053  


Back to the top