Ich möchte meine Spring Boot-App so konfigurieren, dass alle 404 nicht gefundenen Anforderungen an meine Einseiten-App umgeleitet werden.
Wenn ich beispielsweise localhost:8080/asdasd/asdasdasd/asdasd
anrufe, der nicht vorhanden ist, sollte er zu localhost:8080/notFound
umgeleitet werden.
Das Problem ist, dass ich eine einzelne Seitenreaktions-App habe und sie im Wurzelpfad localhost:8080/
läuft. Der Frühling sollte also zu localhost:8080/notFound
umleiten und dann zu /
weiterleiten (um die Route zu behalten).
Dies sollte den Trick ausführen: Fügen Sie eine Fehlerseite für 404 hinzu, die zu /notFound
weiterleitet, und leiten Sie diese an Ihr SPA weiter (vorausgesetzt, der Eintrag befindet sich auf /index.html
):
@Configuration
public class WebApplicationConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/notFound").setViewName("forward:/index.html");
}
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/notFound"));
};
}
}
Dies ist das vollständige Spring Boot 2.0-Beispiel:
@Configuration
public class WebApplicationConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/notFound").setViewName("forward:/index.html");
}
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND,
"/notFound"));
};
}
}
Falls hier jemand stolpert und nach Wegen sucht, wie Angular/React/andere Routen und Pfade in einer Spring Boot-App zu handhaben sind - aber nicht immer index.html für einen beliebigen 404-Server zurückgibt - kann dies in einem Spring-RequestMapping-Standard-Controller erfolgen. Dies kann ohne Hinzufügen von View-Controllern und/oder Anpassen der Container-Fehlerseite erfolgen.
Das RequestMapping unterstützt Platzhalter, sodass Sie es mit einer Reihe bekannter Pfade (z. B. eckige Routen usw.) in Ihrer Anwendung abgleichen können.
@Controller
public class Html5PathsController {
@RequestMapping( method = {RequestMethod.OPTIONS, RequestMethod.GET}, path = {"/path1/**", "/path2/**", "/"} )
public String forwardAngularPaths() {
return "forward:/index.html";
}
}
Eine weitere Option (aus einem alten Spring-Artikel hier geliehen: https://spring.io/blog/2015/05/13/modularizing-the-client-angular-js-and-spring-security-part-vii ) ist eine Namenskonvention zu verwenden:
@Controller
public class Html5PathsController {
@RequestMapping(value = "/{[path:[^\\.]*}")
public String redirect() {
return "forward:/index.html";
}
}
Die obige Konfiguration stimmt mit allen Pfaden überein, die keine Periode enthalten und nicht bereits einem anderen Controller zugeordnet sind.
//add this controller : perfect solution(from jhipster)
@Controller
public class ClientForwardController {
@GetMapping(value = "/**/{path:[^\\.]*}")
public String forward() {
return "forward:/";
}
}
Hier die Sicherheitskonfiguration (SecurityConfig.Java)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private Environment env;
@Autowired
private UserSecurityService userSecurityService;
private BCryptPasswordEncoder passwordEncoder() {
return SecurityUtility.passwordEncoder();
}
private static final String[] PUBLIC_MATCHERS = {
"/css/**",
"/js/**",
"/data/**",
"/sound/**",
"/img/**",
"/",
"/login",
"/logout,
"/error",
"/index2",
};
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().
/* antMatchers("/**").*/
antMatchers(PUBLIC_MATCHERS).
permitAll().anyRequest().authenticated();
//.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login");
http
.csrf().disable().cors().disable()
.formLogin().failureUrl("/login?error")
.defaultSuccessUrl("/index2")
.loginPage("/login").permitAll()
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout").deleteCookies("remember-me").permitAll()
.and()
.rememberMe()
.and()
.sessionManagement().maximumSessions(3600)
.and().
invalidSessionUrl("/login");
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userSecurityService).passwordEncoder(passwordEncoder());
}
}
Wird keine Ressource zur Fehlerseite gefunden
@Controller
public class IndexController implements ErrorController{
private static final String PATH = "/error";
@RequestMapping(value = PATH)
public String error() {
return PATH;
}
@Override
public String getErrorPath() {
return PATH;
}
}
Fehlerseite wie
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1000/xhtml"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<meta http-equiv="refresh" content="5;url=/login" />
<body>
<h1>Page not found please login the system!</h1>
</body>
</html>
Einfache Implementierung des org.springframework.boot.web.servlet.error.ErrorController hat den Trick für mich getan. Ich benutze SpringBoot 2.0 mit React. (Wenn Sie daran interessiert sind, hier ein Boilerplate-Projekt von mir: https://github.com/archangel1991/react-with-spring )
@Controller
public class CustomErrorController implements ErrorController {
@Override
public String getErrorPath() {
return "/error";
}
}
Ich bin mir nicht sicher, warum das so ist.