Routing Single Page Application w Spring Boot

0

Witam wszystkich,

Napisałem sobie front w VueJS (SPA, vue-router), wygenerowałem pliki js/css itd i wrzuciłem je do katalogu resources/static w moim projekcie Spring Boot. Wszystko działa okej, ale jeśli użytkownik jest np. na stronie /login i da odśwież w przeglądarce, wywali mu stronę 404 Not Found.

Próbuję przekierować cały ruch na index.html tak żeby routingiem zajął się vue-router, niestety mam z tym pewne problemy.

Próbowałem @RequestMapping na wzór https://spring.io/guides/tutorials/spring-security-and-angular-js/ Using "Natural" Routes, ale działa tylko dla jednego /, np. strona /project/edit/33 wywali znowu 404 Not Found.
Wszelkie moje próby z /* i /** kończyły się nieskończoną pętlą. Również przy nadpisywaniu view controllera.

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/{path:\\w+}")
                .setViewName("forward:/");
        registry.addViewController("/{path:?!(oauth)$}/*")
            .setViewName("forward:/");        
    }
}

W jaki sposób mogę przekierować cały ruch na index.html bez nadpisywania restowych controllerów?

0

A czemu /login nie jest częścią aplikacji javascriptowej?

0

@xLatency: jest. I działa dobrze, jeśli forwarduję request z /login na index.html:

    @RequestMapping(value = {"/login", "/projekty"}, method = RequestMethod.GET)
    public String forwardRequests() {
        return "forward:/";
   }

Problem w tym, że nie wiem jak forwardować wszystkie requesty. Jak dam '/*', albo '/**' to wpadam w nieskończoną pętlę.

0

A dlaczego użytkownik trafia na stronę /login? Nigdy nie powinien tam trafić.

0

@xLatency: np. wpisując adres /login bezpośrednio w przeglądarce. Wtedy dostanie whitelabel page z 404. Dlatego potrzebuję forward, żeby wskazać na index.html, ale nie zmienić adresu w przeglądarce, tak aby vue-router wiedział, którą stronę otworzyć.

Nie wiem jak przechwycić wszystkie requesty, żeby nie zapętlić.

1

Nie mieszaj routowania aplikacji JS z routowaniem backendu. Niech aplikacja JS zajmuje się routowaniem i wyświetlaniem HTML, a backend zwraca odpowiednie dane z endpointów zaczynających się np. od /api/* albo /rest/*. Mniej więcej tak, jak jest to pokazane w przykładzie, do którego link dałeś w pierwszym poście.

0

@c3r: Tak, tylko tak jak napisałem w pierwszym poście, moja aplikacja JS znajduje się wewnątrz aplikacji Spring Boot, którą chcę deployować na produkcję. Dlatego potrzebuję oba te routowania ze sobą pogodzić. Tzn. Spring musi forwardować wszelkie requesty na index.html, a tam JS zajmie się resztą.

Ustawiam tak:

    @RequestMapping(value = "/{path:[^\\.]*}")
    public String redirect() {
        return "forward:/";
    }
  • /login przekierowuje na stronę login -> OK
  • /project przekierowuje na stronę projektów -> OK
  • /project/add zwraca Whitelabel Error Page 404 -> BŁĄD
  • /project/edit/33 zwraca Whitelabel Error Page 404 -> BŁĄD
  • /ouath/token prawidłowo autoryzuje -> OK

No więc kombinuję różne ścieżki na pałę i nic mi nie wychodzi, na ogół się zapętlam.

Najbliższy działający kod jaki udało mi się uzyskać:

@Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
        registry.addViewController("/{path:\\w+}")
                .setViewName("forward:/");
        registry.addViewController("/**/{path:\\w+}")
                .setViewName("forward:/");
        registry.addViewController("/oauth/**").setViewName("authorize");
}
  • /login przekierowuje na stronę login -> OK
  • /project przekierowuje na stronę projektów -> OK
  • /project/add przekierowuje na stronę dodawania projektów -> OK
  • /project/edit/33 przekierowuje na stronę edycji projektu -> OK
  • /ouath/token zwraca błąd {"timestamp":"2018-02-05T07:53:05.721+0000","status":405,"error":"Method Not Allowed","exception":"org.springframework.web.HttpRequestMethodNotSupportedException","message":"Request method 'POST' not supported","path":"/oauth/token"}

Jak skonfigurować te przekierowania tak, aby nie nadpisać endpointów z security?

PS. Ze wszystkimi endpointami /rest/* nie mam problemu, bo mają one zdefiniowaną konkretną ścieżkę w kontrolerach, więc AntPathMatcher mapuje je odpowiednio.

0

Bez sensu. Po co chcesz wszystko przekierować na index.html? Wystarczy że root aplikacji będzie przekierowany na index html:

new WebMvcConfigurerAdapter() {

            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("forward:/index.html");
            }
        };
0

@xLatency: Po to, że jak użytkownik wpisze w przeglądarce http://mojadomena.pl/login to zamiast wejść na stronę logowania dostanie Whitelabel Error Page 404 prosto na twarz :)

Poza tym kod powyżej w Spring Boocie jest niepotrzebny, bo defaultowo jest wskazywana strona index.html w katalogu /resource/static, /resource/public itp.

0

No dobra a próbowałeś tak:

    @RequestMapping("/{path:[^\\.]+}/**")
    public String forward() {
        return "forward:/";
    }
0

Tak, nie działa, bo nie można załadować javascriptów, więc wyświetla tylko białą pustą stronę. Np. http://localhost:8080/static/js/app.53e878b69864a2f449bd.js zamiast pliku .js zwraca index.html.

0

Próbowałem jeszcze tak:

    @RequestMapping(value = {"/{path:[^\\.]*}", "/**/{path:[^\\.]*}"}, method = RequestMethod.GET)
    public String forward() {
        return "forward:/";
    }

Teraz wszystkie strony przekierowuje prawidłowo, tylko znowu mi nadpisuje endpoint z oauth, który zwraca:

{  
   "timestamp":"2018-02-05T09:13:28.104+0000",
   "status":405,
   "error":"Method Not Allowed",
   "exception":"org.springframework.web.HttpRequestMethodNotSupportedException",
   "message":"Request method 'POST' not supported",
   "path":"/oauth/token"
}
0

A jak masz zdefiniowany endpoint do security (oauth) ?

0

Nie definiowałem ich, framework je sam wystawia przy włączonym security.

Próbowałem tak:

registry.addViewController("/oauth/**").setViewName("authorize");

ale to zwyczajnie nie działa :)

2

OK, metodą prób i błędów wykombinowałem.

    @RequestMapping(value = {"/{path:[^\\.]*}", "/**/{path:^(?!oauth).*}/{path:[^\\.]*}"}, method = RequestMethod.GET)
    public String forward() {
        return "forward:/";
    }

W ten sposób wszelkie linki są forwardowane na index.html, pliki statyczne jak .js, .css, .img są serwowane bezpośrednio z katalogu, a endopointy z security zaczynające się od /oauth nie są nadpisywane.

Dodatkowo jeśli komuś kolidowałoby z innymi linkami z frameworka, np. z /health może zmienić regex na /**/{path:^(?!oauth|health).*}/{path:[^\\.]*} itp. Z pozostałymi endpointami, które mają ściślej określoną ścieżkę, nie powinno być problemu. AntPathMatcher się tym zajmuje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1