配置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&lt;ConfigurableServletWebServerFactory&gt; 这就是答案!谢谢。 你能用@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重定向到单页应用程序[重复]的主要内容,如果未能解决你的问题,请参考以下文章

【Django】路由配置:反向解析、重定向

在NodeNS中,如何重定向到单页面应用程序中的特定页面?

angular---路由之重定向路由

如何强制将所有 404(或每个页面,无论是不是无效)重定向到主页?

如何使用web.config将所有.asp页面重定向到IIS上的.php页面

spring-bootspring-boot项目中,通过JAVA配置类形式配置前台代码都重定向转发