我想配置我的Spring Boot应用程序,将任何404未找到的请求重定向到我的单页应用程序。
例如,如果我调用不存在的localhost:8080/asdasd/asdasdasd/asdasd
,它应该重定向到localhost:8080/notFound
。
问题是我有一个单页反应应用程序,它运行在根路径localhost:8080/
。所以春天应该重定向到localhost:8080/notFound
,然后转发到/
(保持路线)。
这应该可以解决这个问题:添加404路由到/notFound
的错误页面,并将其转发到SPA(假设条目位于/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"));
};
}
}
这是完整的Spring Boot 2.0示例:
@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"));
};
}
}
如果有人在这里偶然发现如何处理Spring Boot应用程序中的Angular / React /其他路由和路径 - 但并不总是返回任何404的index.html - 它可以在标准的Spring控制器RequestMapping中完成。这可以在不添加视图控制器和/或自定义容器错误页面的情况下完成。
RequestMapping支持通配符,因此您可以使其与应用程序中的一组众所周知的路径(即角度路径等)匹配,然后返回index.html:
@Controller
public class Html5PathsController {
@RequestMapping( method = {RequestMethod.OPTIONS, RequestMethod.GET}, path = {"/path1/**", "/path2/**", "/"} )
public String forwardAngularPaths() {
return "forward:/index.html";
}
}
另一种选择(借用旧的Spring文章:https://spring.io/blog/2015/05/13/modularizing-the-client-angular-js-and-spring-security-part-vii)是使用命名约定:
@Controller
public class Html5PathsController {
@RequestMapping(value = "/{[path:[^\\.]*}")
public String redirect() {
return "forward:/index.html";
}
}
上述配置将匹配所有不包含句点且尚未映射到另一个控制器的路径。
这里的安全配置(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());
}
}
如果未找到任何资源重定向到错误页面
@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;
}
}
错误页面就像
<!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>
简单地实现org.springframework.boot.web.servlet.error.ErrorController就可以解决这个问题了。我将SpringBoot 2.0与React一起使用。 (如果您对如何做到这一点感兴趣,请参考我制作的样板项目:https://github.com/archangel1991/react-with-spring)
@Controller
public class CustomErrorController implements ErrorController {
@Override
public String getErrorPath() {
return "/error";
}
}
我不知道为什么这会起作用。