RequestMapping issue with multiple Angular clients

2020-03-31 17:39发布

问题:

I need to handle some GET requests in order to forward to multiple Angular clients.

https://example.com/web/index.html    // Client 1
https://example.com/admin/index.html  // Client 2

Since I don't want to use fragmented (#-ed) paths for /web things get rather annyoing.

This is my current not working solution:

@Controller
public class ForwardController {

    @RequestMapping(value = "/*", method = RequestMethod.GET)
    public String redirectRoot(HttpServletRequest request) {

        String req = request.getRequestURI();

        if (req.startsWith("/admin/")) {
            return this.redirectAdminTool(request);
        }

        return "forward:/web/index.html";
    }

    @RequestMapping(value = "/web/{path:[^.]*}", method = RequestMethod.GET)
    public String redirectWeb(HttpServletRequest request) {
        return "forward:/web/index.html";
    }

    @RequestMapping(value = "/admin/{path:[^.]*}", method = RequestMethod.GET)
    public String redirectAdminTool(HttpServletRequest request) {
        return "forward:/admin/index.html";
    }
}

With this, what does work is accessing e.g.

  • /web/pricing

but what does not work is accessing

  • /web/pricing/vienna

I can access /web/pricing via browser, hit "refresh" and everything will work. But it does not for /web/pricing/vienna.

Now, I cannot figure out how to handle the requests and how to forward them in order to make sub-paths like /web/pricing/vienna to work as well.

Is there any way I can make this work?

If I change the @RequestMapping path to something like /web/** the whole thing ends up in an endless loop and breaks the server.


What I probably need is an expression like this:

/web(/[^\\.]*)

which would result in

MATCH:    /web/pricing
MATCH:    /web/specials/city
MATCH:    /web/specials/city/street
NO MATCH: /web/index.html

However, Spring does not like this regex: /web(/[^\\.]*)

In the end this issue boils down to finding a way to match everythign except static resources below /web.

回答1:

Here is what I ended up doing:

I moved both clients to a subdirectory a/:

static/a/web
static/a/admin

Further, I implemented a ForwardController like this:

@Controller
public class ForwardController {

    @RequestMapping(value = "/*", method = RequestMethod.GET)
    public String redirectRoot(HttpServletRequest request) {
        return "forward:/a/web/index.html";
    }

    @RequestMapping(value = "/a/**/{path:[^.]*}", method = RequestMethod.GET)
    public String redirectClients(HttpServletRequest request) {

        String requestURI = request.getRequestURI();

        if (requestURI.startsWith("/a/admin/")) {
            return "forward:/a/admin/index.html";
        }

        return "forward:/a/web/index.html";
    }

}


回答2:

The child routes will not work because the main index needs to be loaded before, to get all the routes. A workaround is to redirect to the main index everytime the server side does not find a path:

@Controller
@RequestMapping("/error")
public class ErrorHandlerController extends AbstractErrorController {

private static final String ROOT_PATH = "/";

public ErrorHandlerController(ErrorAttributes errorAttributes) {
    super(errorAttributes);
}

@RequestMapping
public void errorHtml(HttpServletRequest request,
        HttpServletResponse response) throws IOException {
    if(HttpStatus.NOT_FOUND.equals(getStatus(request))) {
        response.sendRedirect(ROOT_PATH);
    }
}

@Override
public String getErrorPath() {
    return "error";
}

}