配置spring boot以将404重定向到单页应用程序[重复]
Posted
技术标签:
【中文标题】配置spring boot以将404重定向到单页应用程序[重复]【英文标题】:Configure spring boot to redirect 404 to a single page app [duplicate] 【发布时间】:2017-11-25 08:13:11 【问题描述】:我想将我的 Spring Boot 应用程序配置为将任何 404 未找到请求重定向到我的单页应用程序。
例如,如果我调用不存在的localhost:8080/asdasd/asdasdasd/asdasd
,它应该重定向到localhost:8080/notFound
。
问题是我有一个单页反应应用程序,它在根路径localhost:8080/
中运行。所以spring应该重定向到localhost:8080/notFound
,然后转发到/
(保持路由)。
【问题讨论】:
您的 Spring Boot 应用程序是否提供声明资源;如果是这样,您是否在 Boot 中做了一些特殊的配置来配置它,或者您是否依赖默认设置?你不觉得这种行为是不正确的吗?用 HTTP 200 OK 和你的索引页面回复 all 请求,即使资源显然不存在? 我猜你应该考虑使用 React 重定向到未知页面,详情请参阅this questions 这能回答你的问题吗? Spring boot with redirecting with single page angular2 【参考方案1】:这是完整的 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"));
;
【讨论】:
好吧,似乎有效。但是,即使后端请求返回 404,它也会返回 index.html。我怎样才能避免这种情况? @dave0688 - 您可以使用与应用程序中一组众所周知的路径(即角度路由等)匹配的标准休息控制器请求映射,并使用它返回前向 index.html:@ 987654322@ @joensson - 这应该被接受,因为它保留了 404 页面的可能性。谢谢。 @MaksimMaksimov 谢谢,我将其添加为此页面的建议答案。 (尽管从技术上讲,OP 特别要求提供重定向任何 404 的解决方案,因此他可能不同意 :-))forward:/index.html
导致 index.html 页面显示为 Spring Boot 而不是 SPA 中的 404 页面/组件。【参考方案2】:
这应该可以解决问题:为 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 V2(目前正在开发中,2.0.0.M7)中,EmbeddedServletContainerCustomizer
已更改为 WebServerFactoryCustomizer
。 bean containerCustomizer
的签名将是 WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
这就是答案!谢谢。
你能用@ExceptionHandler(ResourceNotFoundException.class)
得到同样的结果吗?
在 Spring Boot 2 的版本中编辑。在这里工作得很好!
在 Spring Boot 2.0.2.RELEASE container.addErrorPages
不是有效方法【参考方案3】:
如果有人在这里偶然发现如何在 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";
上述配置将匹配所有不包含句点且尚未映射到另一个控制器的路径。
【讨论】:
这是否只匹配根路径上的路径,例如/
、/about
等而不匹配/cars/berlin
?
如果我将其更改为"/[path:[^\.]*/**"
,我可以导航到子路由,但不再加载 CSS 文件。 ://
@RequestMapping(value = "/[path:[^\\.]*")
或类似的东西对我不起作用。有人得到了功能性的东西吗?
@GarouDan 我认为spring博文中可能存在语法错误。尝试删除路径前的 [ - @RequestMapping(value = "/path:[^\\.]*")。如果这没有帮助,我建议你看看这个线程github.com/spring-guides/tut-spring-security-and-angular-js/… - 他们讨论了这个问题。我链接到的评论显示了如何使用 servlet 过滤器,例如
要修复嵌套路径的解决方案,您可以使用类似 @RequestMapping( "/path:[^\\.]*", "/path1:[^\\.]*/path2:[^\\.]*", ..., "/path1:[^\\.]*/path2:[^\\.]*/path3:[^\\.]*/path4:[^\\.]*/path5:[^\\.]*")
【参考方案4】:
//add this controller : perfect solution(from jhipster)
@Controller
public class ClientForwardController
@GetMapping(value = "/**/path:[^\\.]*")
public String forward()
return "forward:/";
【讨论】:
虽然这段代码 sn-p 可以解决问题,但它没有解释为什么或如何回答这个问题。请include an explanation for your code,因为这确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。 我们应该尽量避免在容易受到 ReDOS 攻击的地方使用正则表达式。 与其他答案相比,此解决方案的一些优点: * 简单的解决方案(不需要 @Bean 覆盖、扩展或实现) * 不使用已弃用的类(例如WebConfigurerAdapter
) * 处理子路径(例如 / users/42) * 不需要保持客户端路由列表与后端同步(例如 path = /path1/**, /path2/**
* 保持后端请求的标准 404 处理【参考方案5】:
这里是安全配置(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>
【讨论】:
【参考方案6】:简单地实现 org.springframework.boot.web.servlet.error.ErrorController 对我有用。我使用带有 React 的 SpringBoot 2.0。 (如果您对如何做到这一点感兴趣,这是我制作的样板项目:https://github.com/archangel1991/react-with-spring)
@Controller
public class CustomErrorController implements ErrorController
@Override
public String getErrorPath()
return "/error";
我不知道为什么这是有效的。
【讨论】:
如果您使用带有自动配置的 Spring Boot 2,那么您实际上应该能够完全删除该 CustomErrorController。如果您查看 ErrorMvcAutoConfiguration,您可以看到它有一个条件 bean,如果没有找到 ErrorController 实现,它会创建一个 BasicErrorController。在 BasicErrorController 中,它有这个请求映射@RequestMapping("$server.error.path:$error.path:/error")
- 所以如果你没有在配置中指定 server.error.path 或 error.path 属性,那么它实际上应该默认为 /error。以上是关于配置spring boot以将404重定向到单页应用程序[重复]的主要内容,如果未能解决你的问题,请参考以下文章
如何强制将所有 404(或每个页面,无论是不是无效)重定向到主页?