React路由与Apache配置

一、前言

        我们知道,React是一个用来开发单页面的Javascript库。如果想让它实现多页面那样的功能,就需要用到路由。然而,路由是一个虚拟目录,并不是真实目录,页面挂载在Apache下必须进行重定向设置,否则会找到不对应的文件。

        有时,我们需要将打包好的页面挂载在Apache二级目录下,这时会报错找不到对应的资源。不管你搜索google还是baidu,都只能搜出Apache二级目录的重定向方法,离实际解决问题总会差那么一点点。不同工程,网页的路由实现是千差万别的,想要正确应用,必须自己摸索对应的方法,有时也需要对前端web代码作出一些修改。

        本文应用于React的Material UI框架中的Admin & Dashboard 模板(我经常使用的一个模板,有免费和收费两种版本)为实例,主要介绍了将React打包好的包含路由功能的页面部署在Apache二级目录下的方法,同时也给出了直接挂载到根目录的方法。本文属于个人经验分享,希望能为大家提供一点点参考,欢迎广大开发者进一步改进完善。

二、预备知识

        Apache下的目录如果想实现重定向,必须进行相应的配置。这里有两种方法:

  1. 在目录下的.htaccess文件里放置指令。一般适用于虚拟主机等没有修改Apache配置权限的场景。
  2. 在Apache主配置里进行修改。比如以Mac OS系统为例,配置文件为/etc/apache2/httpd.conf,记得修改前作好备份。其指令与.htaccess文件中的指令是等价的,但是它更加高效。因为它只在Apache启动时读取一次,而不是每次请求时都读取。

        这里也有几点要注意的地方:

  • .htaccess文件中的配置指令作用于当前目录和所有子目录。需要注意的是,其上级目录也可能存在.htaccess文件,而指令是按从下到上的查找顺序生效的。因此,即子目录中的指令会覆盖父目录或者主配置文件中的指令。
  • 如果在.htaccess文件中的某些指令不起作用,可能有多种原因,但最常见的原因是Apache配置文件里AllowOverride没有被正确设置。一般在虚拟主机上,配置文件中主目录的AllowOverride属性都设置为All。有一个简单的测试方法,就是在.htaccess文件中随便写点什么,如果服务器没有报错,那么几乎可以断定设置了 AllowOverride None

        本文采用常用的使用.htaccess文件的方法来处理重定向请求。

三、Material Dashboard React简要介绍

        下面是Material Dashboard React的截图。这个模板主要用作后台管理,它的左侧有一个导航栏,每个栏目对应一个路由,这正是我们经常要使用的。
React路由与Apache配置_第1张图片
        模板下载地址 => https://themes.material-ui.com/

        类似的模板也有Vue版本,使用Vue的小伙伴们不要错过哟,这里放出地址:
        一些Vue模板地址 => https://www.creative-tim.com/templates/vuejs

        下载模板源码后使用编辑器打开(Atom或者Visual Studio Code),src/routes.js就是页面左边的栏目定义了,这里是其中一项的代码片断:

{
    path: "/dashboard",
    name: "Dashboard",
    rtlName: "لوحة القيادة",
    icon: Dashboard,
    component: DashboardPage,
    layout: "/admin"
  }

        src/layouts/Admin.jsx是代码中具体的路由定义:

const switchRoutes = (
  <Switch>
    {routes.map((prop, key) => {
      if (prop.layout === "/admin") {
        return (
          <Route
            path={prop.layout + prop.path}
            component={prop.component}
            key={key}
          />
        );
      }
      return null;
    })}
    <Redirect from="/admin" to="/admin/dashboard" />
  </Switch>
);

最后是程序的入口,在src/index.js中:

ReactDOM.render(
  <Router history={hist}>
    <Switch>
      <Route path="/admin" component={Admin} />
      <Route path="/rtl" component={RTL} />
      <Redirect from="/" to="/admin/dashboard" />
    </Switch>
  </Router>,
  document.getElementById("root")
);

        有兴趣的同学可以直接npm install,然后npm start体验一下。

        存在的问题

        在开发环境中进行路由切换是没有任何问题的,但是如果npm run build进行打包后将发布版的页面挂在Apache目录下(根目录或者二级目录),就会报错找不到相应的页面(资源)。

        好了,代码中涉及到路由的地方都列出来了,下面我们来解决问题。

四、源码修改与Apache配置

        因为我们一个网站上要挂很多页面,所以一般功能性页面我们是放在二级目录下。这里就以打包后的页面放在二级目录下为例,进行源代码的修改与Apache的配置。

4.1 修改src/index.js中的相关内容

  1. 将第21行导入语句中的Router(不支持basename) 改为BrowserRouter as Router
  2. 在Router属性中增加 basename={process.env.NODE_ENV === 'production' ? '/admin' : ''}
  3. 改为并且移除这一句。

4.2 修改src/routes.js中的相关内容

  1. 将所有的 layout: "/admin" 改为 layout: "/"
  2. 将所有path中的"/"去掉,比如 path: "/dashboard" 改成 path: "dashboard"

4.3 修改src/layouts/Admin.jsx

  1. switchRoutes中的prop.layout === "/admin"改为prop.layout === "/"
  2. switchRoutes中的改成

4.4 修改项目package.json

        修改项目根目录下的package.json文件,将homepage属性的值改为".",意即可以挂在任何目录下。

4.5 创建.htaccess文件

        在Apache根目录下建立二级目录admin,然后在admin文件夹中创建.htaccess文件,内容如下:

RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . admin/index.html [L]

        保存之后记住要 chmod 644 .htaccess

        修改完毕,我们可以使用npm run build来打包,将打包好的文件全部放在Apache二级目录admin下进行测试。

4.6 简要工作流程

  1. 原模板是设计挂在根目录下的(不一定为Apache服务器),但是虚拟主机一般是挂在Apache二级目录下,因此修改了RouterBrowserRouter,增加了basename属性,也就是把路由基准目录设定为该二级目录。
  2. .htaccess中指令的作用是将二级目录下所有的访问转至该目录下的index.html
  3. 转到index.html后,Router发挥作用,进行路由转发,将basename目录(二级目录)下path为"/"的内容(也就是所有内容)转至Admin处理。
  4. Admin中,再进行路由转发,将符合src/routes.js中定义路由转到对应页面。
  5. 如果在Admin中未匹配到对应路由,则执行将内容重定向到dashboard(也就是默认显示的第一个界面),记住这里是重定向,所以url会发生变化。

        警告
        本文中故意忽略了src/index.js中第35行,也没有对此路由进行处理,请大家在实际运用中注意。

4.7 直接挂载在根目录下

        可以看到,为了能挂载到二级目录下,我们手动修改了模板中所有和route相关的代码。我们也可以根据模板设计的初衷,不修改模板代码而直接将打包后的页面挂载在Apache根目录下。此时会报错:

  1. 静态资源找不到,因为静态资源读取的是admin/static目录下的内容。
  2. 根目录使用.htaccess后路由解析报错,原因仍然是找不到静态资源(对应的js文件)
  3. 解决办法:重定向,在.htaccess中再增加一行(第二行)。
RewriteEngine On
Redirect /admin/static /static
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . index.html [L]

        增加的那一行的含义是将所有/admin/static目录下的内容重新定向到/static目录下。笔者测试时出现了一个小缺陷,会报manifest.json出错,但是不影响页面,于是就略过了。

五、总结

        在使用了路由功能的React工程中,可以将打包后的页面挂载在Apache根目录或者二级目录下,此时容易出现资源找不到的情况。挂载到根目录下时通过创建.htaccess指令文件进行资源的重定向来解决。因为根目录只能挂一个页面,所以有时会挂在二级目录下,此时需要使用BrowserRouterg来定义路由的基准目录(为二级目录),并且手动修改route相关的代码,将多余的路径去掉。

欢迎大家留言指正改进或者一起讨论。

你可能感兴趣的:(React)