React类组件路由刷新报错Cannot GET /exams/0的解决方法
解决React类组件路由刷新后「Cannot GET /exams/0」的问题
问题根源
这是单页应用(SPA)的经典路由问题:点击链接时,React Router在客户端完成路由跳转,不会向服务器发送请求;但刷新页面时,浏览器会直接向服务器请求/exams/0这个路径,而你的服务器没有配置对应路径的响应,因此返回404错误。
解决方案
方案1:改用HashRouter(无需服务器配置)
将路由模式切换为哈希模式,URL会带上#(例如/#/exams/0),刷新时浏览器只会请求根路径,React Router会解析#后的部分渲染对应页面。
修改路由配置:
// 替换BrowserRouter为HashRouter import { HashRouter as Router, Routes, Route } from 'react-router-dom'; // 在根组件中用HashRouter包裹路由 class App extends Component { render() { return ( <Router> {/* 你的现有路由结构 */} </Router> ); } }
方案2:配置服务器 fallback 到index.html(保持干净URL)
如果想要不带#的URL,需要配置服务器,让所有请求都返回React应用的index.html,由React Router接管路由处理。
开发环境(Create React App)
在package.json中添加:
"homepage": "."
重启开发服务器即可。
生产环境部署
- Nginx配置:
在nginx.conf的location块中添加:location / { try_files $uri $uri/ /index.html; } - Apache配置:
在项目根目录创建.htaccess文件,添加:RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L]
补充:刷新后加载对应考试内容
解决路由问题后,还需要让DetailedExam组件根据URL中的id加载对应考试数据。由于类组件无法直接使用React Router的hooks,我们可以用高阶组件封装:
import { useParams } from 'react-router-dom'; import { dummyExams } from './FrontPage'; // 导入考试数据 // 高阶组件:给类组件传递路由参数 const withRouter = Component => { const Wrapper = props => { const params = useParams(); return <Component {...props} params={params} />; }; return Wrapper; }; class DetailedExam extends Component { constructor(props) { super(props); this.state = { hasStarted: false, exam: null }; this.startExam = this.startExam.bind(this); } componentDidMount() { // 根据URL中的id获取对应考试 const examId = parseInt(this.props.params.id); const targetExam = dummyExams[examId]; this.setState({ exam: targetExam }); } startExam() { this.setState(prevState => ({ hasStarted: !prevState.hasStarted })); } render() { const { exam } = this.state; if (!exam) return <div>加载中...</div>; return ( <div> <div> <h1>{exam.title}</h1> <p>{exam.content}</p> <div> <span>考试说明...</span> </div> <button onClick={this.startExam}>开始考试</button> </div> </div> ); } } // 用高阶组件包裹组件,获取路由参数 export default withRouter(DetailedExam);
额外修复:FrontPage路由的element格式问题
你的FrontPage组件中,Route的element属性需要用Fragment包裹map返回的数组:
<Route path="/" element={ <> {this.state.exams.map((exam, i) => { return ( <FrontPageExam title={exam.title} text={exam.content} className={this.state.exams.length - i <= 2 ? "Last-Exam" : "Exam"} key={i} setIsExamOpen={this.setIsExamOpen} id={i} /> ); })} </> } />
内容的提问来源于stack exchange,提问作者Ilia Popov
相关产品推荐
相关产品推荐

