React Router部署后直接访问路由出现500内部服务器错误
嘿Anna,我来帮你解决这个生产环境下直接访问React Router子路由出现500错误的问题!
首先得搞明白问题根源:你用的BrowserRouter依赖HTML5的History API,在页面内通过<Link>跳转时是前端自己处理的,完全没问题;但当你复制链接在新窗口打开,或者直接在地址栏输入example.com/mysite/mylink时,请求会先发送到服务器。服务器会默认去寻找/mysite/mylink这个物理文件,但你的React项目本质是单页应用,只有根目录下的index.html是入口文件,服务器找不到对应文件就返回500错误了。
下面给你几种靠谱的解决方案,按推荐程度排序:
这是最标准的解决方案,不同服务器的配置方式如下:
Nginx
修改你的Nginx站点配置,在对应的server块里添加这段规则:
location /mysite { try_files $uri $uri/ /mysite/index.html; }
意思是:当请求/mysite下的任何路径时,先找对应的文件/目录,如果找不到,就返回/mysite/index.html,交给React Router处理前端路由。
Apache
在你的项目部署目录下创建.htaccess文件,写入以下内容:
RewriteEngine On RewriteBase /mysite/ RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /mysite/index.html [L]
这个规则会把所有非真实文件/目录的请求,都重定向到index.html。
Netlify/Vercel等静态托管平台
这些平台自带了单页应用路由支持,只需要在项目根目录创建对应配置文件:
- Netlify:创建
_redirects文件,内容是:/mysite/* /mysite/index.html 200 - Vercel:创建
vercel.json文件,内容是:{ "routes": [ { "src": "/mysite/(.*)", "dest": "/mysite/index.html" } ] }
如果暂时没法修改服务器配置,可以把BrowserRouter换成HashRouter。这种方式下路由会带#,比如example.com/mysite/#/mylink,服务器只会处理/mysite/部分,后面的#/mylink由前端处理,不会触发服务器的文件查找:
import { HashRouter as Router, Switch, Route, Link } from 'react-router-dom'; // 替换原来的BrowserRouter ReactDOM.render( <Provider store={store}> <Router> <Switch> <Route exact path={baseUrl + "..."} ... /> </Switch> </Router> </Provider>, document.getElementById('root') );
缺点是URL会多一个#,不够美观,对SEO也不太友好,所以优先推荐第一种服务器配置方案。
最后确认一下process.env.PUBLIC_URL在生产环境是否确实是/mysite。你可以构建项目后,打开build目录下的index.html,看看静态资源的引用路径是不是/mysite/static/js/xxx.js这种格式。如果PUBLIC_URL配置错误,也可能导致路由和资源加载的问题。
开发环境下create-react-app的dev-server已经默认处理了路由重定向,所以开发时不会遇到这个问题,但生产环境必须自己配置服务器规则哦!
内容的提问来源于stack exchange,提问作者Anna

