Issue
I need a Spring @RequestMapping
that I will use to match all non-/api/...
paths like /products
to forward them to my /
(by return "forward:/";
) view controller which actually serves index.html
contents and causes frontend (React) application to be served so that frontend application can handle this path to render a page.
Please note, that implicitly this @RequestMapping
cannot match /
as it would end up in infinite recurence and StackOverflowError
. It may be worth to exclude index.html
also.
In other words, I want my /api/products
to be handled "locally" by Spring Boot application, where /products/
should be forwarded to render React app. There is not Apache or Nginx proxy - React app is served by Spring thanks to static resource mappings.
I have studied many similar Stackoverflow questions in this area and none of them is working.
Important note: I saw cases on Stackoverflow where the problem only supposed to be resolved, just because initially it looked like working (/products/
forwarded and /api/products
handled by API Controller), but it actually wasn't, because proposed regex was matching everything and /api/products
were handled only by Spring mapping precedences (more specific "wins"), but the same path would actually match the pattern if no other Controller would exist.
This results in inappropriate 404 (or mapping not found) error handling - calling any, even not existing /api/something
endpoint ends up with forward to index.html in all answers that I have found, which I want to avoid. Accessing not existing /api/something
endpoint should rather end up with no handler found Spring error, not in forward. An example of such solution, is the most popular one, like: @RequestMapping(value = "{_:^(?!api).*$}")
The problem is, whatever pattern I try, it ends up with forwarding all of my test cases (like /api
/api/
/api/x
/page/
/page/2
or none.
Just some examples of patterns I have tried:
@RequestMapping(value = "{_:^(?!index\\.html|api).*$}")
@RequestMapping(value = "{x:^(?!api).*$}")
@RequestMapping(value = "/{path:^(?!api/).*$}")
@RequestMapping(value = "/{dataType:^.*(?!api).*$}")
@RequestMapping(value = "/{arg:(?!sitemap.xml|api|index.html).*$}")
@RequestMapping(value = "{arg:^(?!api|!index.html).*$}/**")
@RequestMapping(value = "{_:^(?!index\\.html|api).*$}")
Solution
Looks like the original regex actually works (e.g. "{_:^(?!index\\.html|api).*$}"
).
The problem is, Jetty, to display 404 was internally forwarding to /error
page which also was subject for that controller mapping! Effectively forwarding to frontend app from public resources instead of rendering error page
Answered By - Piotr Müller