如何在SPA React应用程序上正确配置Apache,该应用程序位于使用从React Router构建的嵌套URL的子目录中? [英] How to Properly Configure Apache on a SPA React App that Resides on a Subdirectory that uses Nested URLs built from React Router?
问题描述
我的网站托管在一个子目录中,例如http://mywebsite/admin,其中/admin是子目录
我将我的react应用程序(create-react-app生产版本)上传到/admin子目录中.我还使用react-router v4 BrowserRouter来执行一些简单的客户端路由.以下是我的react-app上的一些相关片段:
index.js
I have my website hosted on a subdirectory, as an example, http://mywebsite/admin, where /admin is the subdirectory
I have my react app (create-react-app production build) uploaded into the /admin subdirectory. I am also using react-router v4 BrowserRouter to have some simple client-side routing performed. Below are some relevant snippets on my react-app:
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"));
App.jsx渲染功能内部
<Route
path='/students'
render={(props) =>
<Students
{...props}
/>
}
/>
<Route
path='/teachers'
render={(props) =>
<Teachers
{...props}
/>
}
/>
导航网站时,一切都很好,并且工作正常,包括嵌套的url,主要是您在代码段中看到的/admin/students
和/admin/teachers
.
All is well and working when navigating the site including the nested urls which are mainly, as you have seen on the snippets, /admin/students
& /admin/teachers
.
主要问题:当我在/admin/teachers
路线上并且刷新页面时,该页面未加载任何内容.仅当我在/admin
路线上时,刷新功能有效.但是不是/admin/teachers
或/admin/students
时.
The main issue: when I am on the /admin/teachers
route and I refresh the page, the page does not load anything. Refreshing works when I am on /admin
route only. But not when it is /admin/teachers
nor /admin/students
.
这不是我第一次使用Apache服务器上托管的react-router v4构建SPA.我已经重用了先前项目中的.htaccess文件.该.htaccess也位于/admin
子目录中.以下是 .htaccess
:
This is not the first time I have built an SPA using react-router v4 hosted on Apache server. I have reused the .htaccess I have on my previous project. This .htaccess also resides at the /admin
subdirectory. Below is the .htaccess
:
.htaccess
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.html?path=$1 [NC,L,QSA]
这会将所有请求路由到由create-react-app生产版本构建的index.html.但是,根据我的调查,这种类型的配置仅适用于不在子目录上且未使用嵌套URL的项目.
This routes all requests to the index.html built by the create-react-app production build. However, upon my investigations, this type of configuration only works on a project that is not on a subdirectory and is not using nested URLs.
请注意,我现在有2个 .htaccess
.一个在根上,另一个在/admin
子目录中.两者都包含相同的 .htaccess
代码.原因是,我在根目录下还有另一个SPA.
Note, that I have 2 .htaccess
now. One on root and another one at the /admin
subdirectory. Both contain the same .htaccess
codes. The reason for this is, I have another SPA running at the root directory.
我想念什么?
如何在SPA React应用程序上正确配置Apache,该应用程序位于使用从React Router构建的嵌套URL的子目录中?
How to Properly Configure Apache on a SPA React App that Resides on a Subdirectory that uses Nested URLs built from React Router?
推荐答案
从根本上解决 OP的答案笔记...
Primarily addressing the OP's answer, plus some other notes...
这是我犯错的地方:
This is where I made a mistake:
请注意,我现在有2个.htaccess.一个扎根,另一个扎根/admin子目录.两者都包含相同的.htaccess代码.原因为此,我在根目录下运行了另一个SPA.
Note, that I have 2 .htaccess now. One on root and another one at the /admin subdirectory. Both contain the same .htaccess codes. The reason for this is, I have another SPA running at the root directory.
这不一定是错误".-您只需要确保使用正确的指令即可.实际上,如果两个 .htaccess
文件打算完全是分开的SPA,则最好将它们分开.
This wasn't necessarily a "mistake" - you would just need to make sure you are using the correct directives. In fact, keeping the two .htaccess
files separate could be preferable if these are intended to be entirely separate SPAs.
要拥有两个独立的-相同的 .htaccess
文件,重点是:
To have two separate - identical - .htaccess
files the important points are:
- 使替换字符串为 relative ,即.没有斜杠前缀.
- 请勿包含
RewriteBase
指令.(这将覆盖目录前缀.)
- Make the substitution string relative, ie. no slash prefix.
- Do not include a
RewriteBase
directive. (Which would override the directory-prefix.)
当 RewriteRule
substitution 字符串是 relative 路径时,则使用目录前缀(即 .htaccess的位置)
文件)添加到重写过程的最后.
When the RewriteRule
substitution string is a relative path then the directory-prefix (ie. the location of the .htaccess
file) is added back at the end of the rewriting process.
因此,/.htaccess
和/admin/.htaccess
都将包含相同的指令:
So, both /.htaccess
and /admin/.htaccess
would contain identical directives:
RewriteEngine on
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) index.html?path=$1 [L,QSA]
但是,此解决方案与OP的解决方案略有不同,URL路径的 admin/
部分未传递给 path
URL参数.如果需要,您可以对此进行硬编码.例如. index.html?path = admin/$ 1
.或在您的脚本中对此进行说明.
HOWEVER, a slight difference with this solution and the OP's solution is that the admin/
part of the URL-path is not passed to the path
URL parameter. You could hardcode this if required. eg. index.html?path=admin/$1
. Or account for this in your script.
第一个 RewriteRule
只是一个较小的优化,可防止在请求已被重写为 index.html
后进一步进行文件系统检查.
The first RewriteRule
is just a minor optimisation that prevents further filesystem checks after the request has already been rewritten to index.html
.
请注意,我将(.*)
(0或更多)更改为(.+)
(1或更多).这样可以避免在请求根目录时进行其他目录检查.IE. example.com/
和 example.com/admin/
.您不是要重写这些请求,而是要依赖正确设置的 DirectoryIndex index.html
-这是服务器配置中的默认设置.
Note that I changed (.*)
(0 or more) to (.+)
(1 or more). This avoids the additional directory check when requesting the root directory. ie. example.com/
and example.com/admin/
. You are not rewriting these requests, but instead are reliant on DirectoryIndex index.html
being set appropriately - this is the default setting in the server config.
由于 substitution 字符串( index.php?page = $ 1
)是相对的,因此在文档根目录中时,它将有效地重写为/index.php
,并且在/admin/.htaccess
中使用时,它将有效地改写回/admin/index.php
.
Since the substitution string (index.php?page=$1
) is relative, when in the document root it will effectively rewrite to /index.php
and when in /admin/.htaccess
it will effectively rewrite back to /admin/index.php
.
请注意,由于默认情况下不继承mod_rewrite指令,因此/admin/.htaccess
中的mod_rewrite指令完全覆盖了父 .htaccess
文件中的mod_rewrite指令.模块).
Note that the mod_rewrite directives in /admin/.htaccess
completely override the mod_rewrite directives in the parent .htaccess
file since mod_rewrite directives are not inherited by default (unlike other modules).
或者,为避免重复,同时仍保持两个单独的 .htaccess
文件,您可以在/admin/.htaccess
文件中启用mod_rewrite继承.例如...
Alternatively, to avoid repetition, whilst still maintaining two separate .htaccess
files you could enable mod_rewrite inheritance in the /admin/.htaccess
file. For example...
在根/.htaccess
文件中:
RewriteEngine on
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) index.html?path=$1 [L,QSA]
然后,在/admin/.htaccess
中,您将获得以下内容:
Then, in /admin/.htaccess
you would have the following instead:
RewriteEngine On
RewriteOptions Inherit
此继承父mod_rewrite指令,就好像它们是原地在/admin/.htaccess
文件中原地复制的一样.
This inherits the parent mod_rewrite directives as if they were literally copied in-place in the /admin/.htaccess
file.
但是,这增加了一层额外的复杂性.除了/admin
中的SPA现在依赖于根 .htaccess
文件之外,您现在还必须注意不要添加任何 breaking 指向根 .htaccess
文件的em>指令.
However, this adds an additional layer of complexity. Apart from the SPA in /admin
now being dependent on the root .htaccess
file, you now have to be careful that you don't add any breaking directives to the root .htaccess
file.
旁边:
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路径中进行检查(顺便说一句,这并不严格检查URL路径中的"admin" -并非严格正确)-可以在 RewriteRule
指令本身.例如:
The first condition that checks for "admin" in the URL-path (incidentally, this checks for "admin" anywhere in the URL-path - which isn't strictly correct) is not required - the check can be performed more optimally in the RewriteRule
directive itself. For example:
RewriteRule ^(admin/.*) admin/index.html?path=$1 [QSA,L]
如果需要的话,可以将这两个规则组合为一个规则,但这可能会牺牲一些清晰度.例如:
These two rules can be combined into one if desired, possibly at the expense of some clarity. For example:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(admin/)?.* $1index.html?path=$0 [QSA,L]
$ 1
后向引用包含可选的路径前缀,或者为 admin/
或 nothing .并且 $ 0
包含完整匹配项.
The $1
backreference then contains the optional path-prefix, either admin/
or nothing. And $0
contains the full match.
这篇关于如何在SPA React应用程序上正确配置Apache,该应用程序位于使用从React Router构建的嵌套URL的子目录中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!