Spring catch all route for index.html

后端 未结 6 1839

I\'m developing a spring backend for a react-based single page application where I\'m using react-router for client-side routing.

Beside the index.html page the back

相关标签:
6条回答
  • 2020-11-29 00:10

    To answer your specific question which involves serving up the Single Page App (SPA) in all cases except the /api route here is what I did to modify Petri's answer.

    I have a template named polymer that contains the index.html for my SPA. So the challenge became let's forward all routes except /api and /public-api to that view.

    In my WebMvcConfigurerAdapter I override addViewControllers and used the regular expression: ^((?!/api/|/public-api/).)*$

    In your case you want the regular expression: ^((?!/api/).)*$

    public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
    
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/{spring:^((?!/api/).)*$}").setViewName("polymer");
        super.addViewControllers(registry);
    }
    

    This results in being able to hit http://localhost or http://localhost/community to serve up my SPA and all of the rest calls that the SPA makes being successfully routed to http://localhost/api/posts, http://localhost/public-api/posts, etc.

    0 讨论(0)
  • 2020-11-29 00:13

    Avoid @EnableWebMvc

    By default Spring-Boot serves static content in src/main/resources:

    • /META-INF/resources/
    • /resources/
    • /static/
    • /public/

    Take a look at this and this;

    Or keep @EnableWebMvc and override addViewControllers

    Did you specify @EnableWebMvc ? Take a look a this: Java Spring Boot: How to map my app root (“/”) to index.html?

    Either you remove @EnableWebMvc, or you can re-define addViewControllers:

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

    Or define a Controller to catch /

    You may take a look a this spring-boot-reactjs sample project on github:

    It does what you want using a Controller:

    @Controller
    public class HomeController {
    
        @RequestMapping(value = "/")
        public String index() {
            return "index";
        }
    
    }
    

    Its index.html is under src/main/resources/templates

    0 讨论(0)
  • 2020-11-29 00:14

    Found an answer by looking at this question

    @Bean
    public EmbeddedServletContainerCustomizer notFoundCustomizer() {
        return new EmbeddedServletContainerCustomizer() {
            @Override
            public void customize(ConfigurableEmbeddedServletContainer container) {
                container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/"));
            }
        };
    }
    
    0 讨论(0)
  • 2020-11-29 00:22

    Since my react app could use the root as forward target this ended up working for me

    @Configuration
    public class WebConfiguration extends WebMvcConfigurerAdapter {
    
      @Override
      public void addViewControllers(ViewControllerRegistry registry) {
          registry.addViewController("/{spring:\\w+}")
                .setViewName("forward:/");
          registry.addViewController("/**/{spring:\\w+}")
                .setViewName("forward:/");
          registry.addViewController("/{spring:\\w+}/**{spring:?!(\\.js|\\.css)$}")
                .setViewName("forward:/");
      }
    }
    

    To be honest I have no idea why it has to be exactly in this specific format to avoid infinite forwarding loop.

    0 讨论(0)
  • 2020-11-29 00:26

    I have a Polymer-based PWA hosted inside of my Spring Boot app, along with static web resources like images, and a REST API under "/api/...". I want the client-side app to handle the URL routing for the PWA. Here's what I use:

    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter {
        /**
         * Ensure client-side paths redirect to index.html because client handles routing. NOTE: Do NOT use @EnableWebMvc or it will break this.
         */
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            // Map "/"
            registry.addViewController("/")
                    .setViewName("forward:/index.html");
    
            // Map "/word", "/word/word", and "/word/word/word" - except for anything starting with "/api/..." or ending with
            // a file extension like ".js" - to index.html. By doing this, the client receives and routes the url. It also
            // allows client-side URLs to be bookmarked.
    
            // Single directory level - no need to exclude "api"
            registry.addViewController("/{x:[\\w\\-]+}")
                    .setViewName("forward:/index.html");
            // Multi-level directory path, need to exclude "api" on the first part of the path
            registry.addViewController("/{x:^(?!api$).*$}/**/{y:[\\w\\-]+}")
                    .setViewName("forward:/index.html");
        }
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/**").addResourceLocations("classpath:/webapp/");
        }
    }
    

    This should work for Angular and React apps as well.

    0 讨论(0)
  • 2020-11-29 00:34

    I use react and react-router in my spring boot app, and it was as easy as creating a controller that has mapping to / and subtrees of my website like /users/** Here is my solution

    @Controller
    public class SinglePageAppController {
        @RequestMapping(value = {"/", "/users/**", "/campaigns/**"})
        public String index() {
            return "index";
        }
    }
    

    Api calls aren't caught by this controller and resources are handled automatically.

    0 讨论(0)
提交回复
热议问题