返回

React Router 部署失效排查与解决方案:Surge/GitHub Pages 404问题

javascript

React Router 在生产环境和 Surge 部署中失效问题排查

使用 React Router 进行单页应用 (SPA) 开发时,常常在本地开发环境运行良好,部署至像 Surge 或 GitHub Pages 等静态托管服务后,会出现路由失效的问题,尤其体现在通过直接 URL 访问特定页面时返回 404 错误。这背后的原因是静态托管服务器与客户端路由机制的不兼容。

问题根源:静态服务器与客户端路由

React Router 的核心功能是处理客户端的路由导航,即应用内的跳转逻辑在浏览器中完成,不会像传统的多页面应用一样每次请求都发送到服务器。当用户直接访问诸如 example.com/signup 这样的 URL 时,托管服务会直接查找名为 signup 的文件,因为这是一个 SPA,该文件并不存在,从而导致 404 错误。这种不兼容性,是生产环境下 React Router 失效的主要原因。

解决方案:配置服务器回退和哈希路由

主要有两个常见的解决方法,选择适合项目的方法进行部署:

方案一:服务器回退配置

通过服务器的重定向规则,当访问的静态文件不存在时,将所有请求重定向至入口文件 index.html,随后,React Router 将接管路由逻辑,正确渲染对应的页面。这种方案需要托管服务器支持重定向配置。

操作步骤:

  1. Surge : 在 public 文件夹内创建一个名为 200.html 的文件,内容和 index.html 完全一致。

  2. GitHub Pages :

    • 创建一个 404.html 文件(内容和 index.html 一样)。GitHub Pages会自动将 404 错误定向到这个文件。
    • package.json 文件里,你的脚本构建命令确保正确: 比如"deploy": "npm run build && cp build/index.html build/404.html", 其中build/index.html 是生产打包出来的index.html文件的路径。
  3. 其他静态服务器
    请参照所使用静态托管服务器的文档,配置类似规则,将 404 错误页面指定为 index.html。例如,一些 Nginx 服务器配置中可采用:

        location / {
            try_files $uri $uri/ /index.html;
        }
    

这种方法让服务器把路由权交还给 React 应用,从而实现页面的正确渲染。注意,重定向设置需要与实际使用的托管服务相匹配。

方案二:哈希路由

哈希路由利用 URL 中的哈希值 (#) 进行路由。例如,example.com/#/signup 。哈希值的改变不会触发页面刷新,而是由客户端 JavaScript 进行处理。由于服务器只处理 # 之前的内容,这种方法能规避服务器查找静态文件的问题。

代码示例:

更改你的 index.js 文件,用 hashHistory 代替 BrowserRouter ( 或者其他使用 history api 的 history),具体代码如下:

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Switch, hashHistory } from 'react-router-dom'; // 使用 hashHistory

import ChatApp from './components/ChatApp';
import SignUp from './components/SignUp';
import Logout from './components/Logout';
import ForgotPassword from './components/ForgotPassword';
import NotFound from './components/NotFound';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';


const App = () => (
  <Router history={hashHistory}> {/* 这里使用了hashHistory */}
        <MuiThemeProvider>
            <Switch>
                <Route exact path="/" component={ChatApp} />
                <Route exact path="/signup" component={SignUp} />
                <Route exact path="/logout" component={Logout} />
                <Route exact path="/forgotpwd" component={ForgotPassword} />
                 <Route exact path="*" component={NotFound} />
            </Switch>
        </MuiThemeProvider>
    </Router>
);

ReactDOM.render(
    <App />,
    document.getElementById('root')
);

重要提示: 使用 hashHistory 有一个局限,哈希路由会导致 SEO 不友好,所以权衡利弊后再做决定。同时确保你的 404 页面设置也正常生效。

关于 404 页面问题

如果在开发环境正常工作的 404 页面在生产环境失效,大概率也是由路由冲突导致。

如果采用第一种解决方案,也就是服务端重定向到 index.html 那么 * 的路由捕获应该能如预期工作。第二种,使用 hashRouter,也同理, * 的捕获正常工作。

安全注意事项

  • 配置服务器回退方案时,务必确保只有 404 错误才被重定向到 index.html。其他资源例如图像或样式文件不能被误导向。
  • 尽可能使用 https,避免 http 直接将敏感信息暴露出来。

两种方案都需要基于项目特点来选择,请结合具体部署环境做出相应调整,解决生产环境的 React Router 路由问题。