ReactJS与Spring Boot单体应用整合时页面刷新出现白标错误问题
React + Spring Boot 单体应用刷新出现白标页的排查与解决方案
问题根因
该问题本质是React客户端路由和Spring Boot服务端路由匹配逻辑冲突导致:
- React使用
BrowserRouter做客户端路由时,路径变化是浏览器端通过History API实现的,不会发起真实的服务端请求 - 页面刷新时,浏览器会直接向Spring Boot发起当前完整路径的GET请求,而Spring Boot没有对应路径的接口/资源映射,就会返回默认的404白标页
排查步骤
- 确认React打包后的
build目录,是否正确放到Spring Boot的src/main/resources/static目录或你自定义的静态资源目录下,静态资源路径配置无错误 - 确认React路由模式:检查是否用的是
BrowserRouter而非HashRouter,HashRouter生成带#的路径,刷新时不会触发服务端请求,一般不会出现该问题 - 直接在浏览器地址栏输入非首页的前端路由路径(比如
http://你的服务地址/dashboard),如果直接返回白标页,即可确定是路由匹配冲突问题
解决方案
方案1:配置Spring Boot视图跳转规则(最常用)
新增Web配置类,将所有非接口、非静态资源的请求都转发到React入口文件index.html,交给客户端处理路由:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { // 匹配一级路径,排除带后缀的静态资源请求 registry.addViewController("/{path:[^\\.]*}") .setViewName("forward:/index.html"); // 匹配多级嵌套路由 registry.addViewController("/**/{path:[^\\.]*}") .setViewName("forward:/index.html"); } }
如果你的后端接口有统一前缀(比如/api),该规则会自动跳过接口请求,不会影响接口调用。
方案2:自定义ErrorController捕获404请求转发
如果不想修改视图规则,也可以自定义错误控制器捕获404请求,统一转发到index.html:
import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @RestController public class CustomErrorController implements ErrorController { @RequestMapping("/error") public ResponseEntity<?> handleError(HttpServletRequest request) { Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); if (statusCode == HttpStatus.NOT_FOUND.value()) { return ResponseEntity.status(HttpStatus.OK) .body("forward:/index.html"); } // 其他错误状态码正常返回 return ResponseEntity.status(statusCode).body("请求错误"); } }
注:Spring Boot 3.x版本中,错误状态码的获取key改为
jakarta.servlet.error.status_code,对应替换即可。
方案3:前端改用HashRouter(改造成本最低)
如果不想修改服务端配置,可以直接把React的路由模式换成HashRouter,生成的路径会自动携带#,刷新时不会向服务端请求#后面的路径,也能解决问题:
// 把原来的BrowserRouter替换为HashRouter即可 import { HashRouter as Router, Routes, Route } from 'react-router-dom'; function App() { return ( <Router> <Routes> {/* 原有路由规则保持不变 */} </Routes> </Router> ); }
内容的提问来源于stack exchange,提问作者Rohinibabu
相关产品推荐
相关产品推荐

