提问者:小点点

如何在SPA React应用程序上正确配置Apache,该应用程序位于使用React路由器构建的嵌套URL的子目录上?


我有我的网站托管在一个子目录,作为一个例子,超文本传输协议://mysite/admin,其中 /admin是子目录

我有我的反应应用程序(创建-反应-应用生产构建)上传到 /admin子目录。我也在使用react-router v4 Browser路由器来执行一些简单的客户端路由。下面是我的反应应用程序上的一些相关片段:

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import { BrowserRouter } from 'react-router-dom';

import './css/custom.css';

ReactDOM.render(<BrowserRouter basename="/admin"><App /></BrowserRouter>, document.getElementById("root"));

内部应用程序。jsx渲染函数

<Route
    path='/students'
    render={(props) =>
        <Students
            {...props}
        />
    }
/>

<Route
    path='/teachers'
    render={(props) =>
        <Teachers
            {...props}
        />
    }
/>

当浏览网站时,包括嵌套的网址,这些网址主要是,正如你在代码片段中看到的,所有这些都是好的和工作的。

主要问题:当我在/admin/teachers路线上时,我刷新页面,页面不会加载任何内容。仅当我在/admin路线上时,刷新才起作用。但不是在/admin/teachers/admin/students时。

这不是我第一次使用Apache服务器上托管的react-router v4构建SPA。我在以前的项目中重用了. htaccess。htaccess也位于/admin子目录中。下面是. htaccess

。htaccess

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.html?path=$1 [NC,L,QSA]

这会将所有请求路由到索引。由CreateReact应用程序生产版本生成的html。但是,根据我的调查,这种类型的配置只适用于不在子目录中且不使用嵌套URL的项目。

注意,我有2个。htaccess现在。一个在根目录下,另一个在/admin子目录下 两者都包含相同的。htaccess代码。原因是,我在根目录下运行了另一个SPA。

我错过了什么?

如何在SPA React应用程序上正确配置Apache,该应用程序位于使用React路由器构建的嵌套URL的子目录上?


共3个答案

匿名用户

主要针对OP的答案,再加上一些其他注释。。。

这就是我犯了一个错误的地方:

注意,我有2个。现在就进入。一个在根目录下,另一个在/admin子目录下。两者都包含相同的内容。HTC访问代码。原因是,我在根目录下运行了另一个SPA。

这不一定是一个“错误”——您只需要确保使用了正确的指令。事实上,保留这两个。htaccess如果这些文件是完全独立的SPA,则最好是单独的文件。

有两个独立的相同的-。htaccess文件要点包括:

  • 使替换字符串相对,即没有斜杠前缀

RewriteRule替换字符串是相对路径时,目录前缀(即.htaccess文件的位置)将添加回重写过程的末尾。

所以,两者都是/。htaccess/admin/。htaccess将包含相同的指令:

RewriteEngine on
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) index.html?path=$1 [L,QSA]

但是,与此解决方案和OP的解决方案稍有不同的是,URL路径的admin/部分没有传递给pathURL参数。如果需要,您可以对其进行硬编码。例如,索引。html?path=admin/$1。或者在脚本中说明这一点。

第一个RewriteRule只是一个小小的优化,它可以防止在请求已被重写到索引后进行进一步的文件系统检查。html

请注意,我将(.*)(0或更多)更改为(.)(1个或多个)。这避免了在请求根目录时进行额外的目录检查。例如。com/示例。com/admin/。您没有重写这些请求,而是依赖于DirectoryIndex。html设置正确-这是服务器配置中的默认设置。

由于替换字符串(index.php?page=$1)是相对的,因此在文档根目录中,它将有效地重写为/index。php和在/admin/中时。htaccess它将有效地重写回/admin/index。php

注意,/admin/中的mod_rewrite指令。htaccess完全覆盖父级中的mod_rewrite指令。htaccess文件,因为mod_重写指令在默认情况下不会继承(与其他模块不同)。

或者,为了避免重复,同时仍保持两个独立的。htaccess文件您可以在/admin/中启用mod_rewrite继承。htaccess文件。例如

在根目录中/。htaccess文件:

RewriteEngine on
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) index.html?path=$1 [L,QSA]

然后,在/admin/。htaccess您将拥有以下内容:

RewriteEngine On
RewriteOptions Inherit

这继承了父mod_rewrite指令,就好像它们是在/admin/中就地复制的一样。htaccess文件。

然而,这增加了额外的复杂性。除了/admin中的SPA现在依赖于root. htaccess文件之外,您现在必须小心不要向root. htaccess文件添加任何中断指令。

旁白:

RewriteCond %{REQUEST_URI} admin
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) admin/index.html?path=$1 [QSA,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.html?path=$1 [QSA,L]

检查URL路径中的admin的第一个条件(顺便说一下,这检查URL路径中的任何地方的admin-这不是严格正确的)是不需要的-检查可以在ReWriteLaw指令本身中更优化地执行。例如:

RewriteRule ^(admin/.*) admin/index.html?path=$1 [QSA,L]

如果需要,这两个规则可以合并成一个,可能以牺牲一些清晰度为代价。例如:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(admin/)?.* $1index.html?path=$0 [QSA,L]

1美元反向引用然后包含可选的路径前缀,要么是admin/,要么什么都没有。并且0美元包含完全匹配。

匿名用户

这就是我犯了一个错误的地方:

注意,我有2个。现在就进入。一个在根目录下,另一个在/admin子目录下。两者都包含相同的内容。HTC访问代码。原因是,我在根目录下运行了另一个SPA。

只需调整我的根。htaccess并删除。htaccess位于/admin子目录中,修复了我的问题中描述的主要问题。

root. htaccess

RewriteCond %{REQUEST_URI} admin
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) admin/index.html?path=$1 [QSA,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.html?path=$1 [QSA,L]

匿名用户

我实际上不知道你问题的答案,但是我可以建议你玩位置指令;类似这样的东西

<Location "/admin">
  RewriteEngine on
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^(.*)$ /admin/index.html?path=$1 [NC,L,QSA]
</Location>

希望这有帮助。