ChatGPT解决这个技术问题 Extra ChatGPT

手动刷新或写入时,React-router URL 不起作用

我正在使用 React-router,当我单击链接按钮时它工作正常,但是当我刷新我的网页时它不会加载我想要的内容。

例如,我在 localhost/joblist,一切都很好,因为我按链接到达这里。但是 if 我刷新了我得到的网页:

Cannot GET /joblist

默认情况下,它不是这样工作的。最初,我的 URL 为 localhost/#/localhost/#/joblist,它们运行良好。但我不喜欢这种 URL,所以试图删除那个 #,我写道:

Router.run(routes, Router.HistoryLocation, function (Handler) {
 React.render(<Handler/>, document.body);
});

localhost/ 不会出现这个问题,这个问题总是返回我想要的。

此应用程序是单页的,因此 /joblist 不需要向任何服务器询问任何内容。

我的整个路由器。

var routes = (
    <Route name="app" path="/" handler={App}>
        <Route name="joblist" path="/joblist" handler={JobList}/>
        <DefaultRoute handler={Dashboard}/>
        <NotFoundRoute handler={NotFound}/>
    </Route>
);

Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});
除非您使用 htaccess 加载您的主要旅游页面并告诉您的路由器使用 location.pathname 它不会工作..
你是怎么擦掉那个 # 符号的?谢谢!
如果您将 React 应用程序托管在 S3 存储桶中,则只需将错误文档设置为 index.html。这将确保无论如何都能命中 index.html
就我而言,它在 Windows 中运行良好,但在 linux 中却不行
这是帮助解决我的问题的参考:github.com/facebook/create-react-app/blob/master/packages/…

S
Stijn de Witt

服务器端与客户端

首先要了解的是,现在有 2 个地方可以解释 URL,而过去只有 1 个。过去,当生活很简单时,一些用户向服务器发送 http://example.com/about 请求,服务器检查 URL 的路径部分,确定用户正在请求 about 页面,然后发回该页面。

使用 React Router 提供的客户端路由,事情就不那么简单了。起初,客户端还没有加载任何 JavaScript 代码。所以第一个请求将永远是服务器。然后,这将返回一个页面,其中包含加载 React 和 React Router 等所需的脚本标签。只有当这些脚本加载后,阶段 2 才会开始。例如,在第 2 阶段,当用户单击“关于我们”导航链接时,URL 会仅在本地更改为 http://example.com/about(通过 History API 实现),但 没有向服务器发出请求。相反,React Router 在客户端做它的事情,决定渲染哪个 React 视图,然后渲染它。假设您的 about 页面不需要进行任何 REST 调用,它已经完成。您已从 首页 切换到 关于我们,而没有触发任何服务器请求。

所以基本上当你点击一个链接时,一些 JavaScript 会运行来操纵地址栏中的 URL,而不会导致页面刷新,这反过来会导致 React Router 在客户端执行页面转换。

但是现在考虑如果您将 URL 复制粘贴到地址栏中并将其通过电子邮件发送给朋友会发生什么。您的朋友尚未加载您的网站。换言之,她仍处于第一阶段。她的机器上还没有运行 React Router。因此,她的浏览器将向 http://example.com/about 发出服务器请求

这就是你的麻烦开始的地方。到目前为止,您只需在服务器的 webroot 中放置一个静态 HTML 即可。但是当从服务器请求时,这会给所有其他 URL 带来 404 错误。这些相同的 URL 在客户端可以正常工作,因为 React Router 正在为您进行路由,但它们在服务器端会失败,除非您让服务器理解它们。

结合服务器端和客户端路由

如果您希望 http://example.com/about URL 在服务器端和客户端都工作,您需要在服务器端和客户端为其设置路由。这是有道理的,对吧?

这就是您的选择开始的地方。解决方案的范围从完全绕过问题,通过返回引导 HTML 的包罗万象的路线,到服务器和客户端都运行相同的 JavaScript 代码的全面同构方法。

完全绕过问题:哈希历史

使用 Hash History 而不是 Browser History,您的关于页面的 URL 将如下所示:http://example.com/#/about

哈希 (#) 符号后面的部分不会发送到服务器。所以服务器只看到 http://example.com/ 并按预期发送索引页面。 React Router 会选择 #/about 部分并显示正确的页面。

缺点:

“丑陋”的网址

使用这种方法无法进行服务器端渲染。就搜索引擎优化 (SEO) 而言,您的网站由一个页面组成,几乎没有任何内容。

包罗万象

使用这种方法,您确实使用了浏览器历史记录,但只需在服务器上设置一个将 /* 发送到 index.html 的包罗万象,从而有效地为您提供与哈希历史记录大致相同的情况。但是,您确实有干净的 URL,您可以稍后改进此方案,而不必使所有用户的收藏夹无效。

缺点:

设置更复杂

仍然没有好的SEO

杂交种

在混合方法中,您通过为特定路线添加特定脚本来扩展包罗万象的方案。您可以制作一些简单的 PHP 脚本来返回您网站中最重要的页面以及包含的内容,这样 Googlebot 至少可以看到您页面上的内容。

缺点:

设置更复杂

只有那些你给予特殊待遇的路线才有好的 SEO

复制用于在服务器和客户端上呈现内容的代码

同构

如果我们使用 Node.js 作为我们的服务器以便我们可以在两端运行相同的 JavaScript 代码会怎样?现在,我们在一个 react-router 配置中定义了所有路由,我们不需要复制渲染代码。这就是所谓的“圣杯”。如果页面转换发生在客户端,服务器会发送与我们最终发送的完全相同的标记。该解决方案在 SEO 方面是最佳的。

缺点:

服务器必须(能够)运行 JavaScript。我已经尝试将 Java 与 Nashorn 结合使用,但它对我不起作用。实际上,这主要意味着您必须使用基于 Node.js 的服务器。

许多棘手的环境问题(在服务器端使用窗口等)

陡峭的学习曲线

我应该使用哪个?

选择一个你可以逃脱的。就个人而言,我认为包罗万象很容易设置,所以这将是我的最低要求。此设置允许您随着时间的推移改进事物。如果你已经在使用 Node.js 作为你的服务器平台,我肯定会研究做一个同构应用程序。是的,一开始很难,但一旦你掌握了窍门,它实际上是解决问题的一个非常优雅的解决方案。

所以基本上,对我来说,这将是决定因素。如果我的服务器在 Node.js 上运行,我会选择同构;否则,我会选择包罗万象的解决方案,并随着时间的推移和 SEO 需求的需要对其进行扩展(混合解决方案)。

如果您想了解更多关于使用 React 进行同构(也称为“通用”)渲染的信息,这里有一些很好的教程:

使用同构应用程序应对未来

在 ReactJS 中创建同构应用程序的痛苦和快乐

如何实现 Node + React 同构 JavaScript 及其重要性

另外,为了让您入门,我建议您查看一些入门工具包。选择一个与您的技术堆栈选择相匹配的技术堆栈(请记住,React 只是 MVC 中的 V,您需要更多的东西来构建完整的应用程序)。首先查看 Facebook 自己发布的内容:

创建反应应用

或者从社区中选择一个。现在有一个不错的网站试图索引所有这些:

选择你完美的 React 入门项目

我从这些开始:

React 同构入门套件

React Redux 通用热门示例

目前,我正在使用受上述两个入门套件启发的自制版本的通用渲染,但它们现在已经过时了。

祝你的任务好运!


伟大的职位斯蒂恩!你会推荐使用同构反应应用程序的入门工具包吗?如果是这样,你能举一个你更喜欢的例子吗?
@Paulos3000 这取决于您使用的服务器。基本上,您为 /* 定义一个路由并使其响应您的 HTML 页面。这里棘手的事情是确保您不会使用此路由拦截对 .js 和 .css 文件的请求。
@Paulos3000 有关一些相关问题,请参见此处:for Apache/phpfor Express/jsfor J2E/Java
@Stijn de Witt 这是一个很好的澄清,并在这个主题上得到了很好的回答。但是,当您的应用程序可以在子目录中提供时(例如通过 iis),有哪些选项。即:domain/appName/routeNamedomain/appName/subfolder/routeName
@LeonGaban 似乎自从写了这个答案以来,React Router 改变了他们的实现。他们现在有不同的路由器实例用于不同的历史记录,并且他们在后台配置历史记录。基本原理还是一样的。
A
Alan W. Smith

如果您使用 Apache 作为您的网络服务器,您可以将其插入到您的 .htaccess 文件中:

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

我正在使用 react: "^16.12.0"react-router: "^5.1.2" 这种方法是万能的,可能是让您入门的最简单方法。


这很好用!如果您不想重组您的应用程序,最简单的方法
不要忘记 RewriteEngine On 作为第一行
请注意,此答案是指 Apache 服务器上的配置。这不是 React 应用程序的一部分。
谁能帮我?这个htaccess放在哪里?添加文件后是否需要 npm run build ?
@TayyabFerozi 您必须确保 RewriteBase 和最后一个 RewriteRule 之后的路径与应用程序所在的文件夹匹配(如果它是子文件夹)
P
Peter Mortensen

这里的答案都非常有帮助。配置我的 Webpack 服务器以期望路由对我有用。

devServer: {
   historyApiFallback: true,
   contentBase: './',
   hot: true
},

historyApiFallback 为我解决了这个问题。现在路由工作正常,我可以刷新页面或直接输入 URL。无需担心 Node.js 服务器上的变通方法。这个答案显然只有在您使用 Webpack 时才有效。

请参阅 my answer to React-router 2.0 browserHistory doesn't work when refreshing 了解为什么需要这样做的更详细原因。


请注意,Webpack 团队 recommends against 在生产中使用开发服务器。
对于通用开发目的,这是最好的解决方案。 historyApiFallback 就足够了。至于所有其他选项,也可以使用标志 --history-api-fallback 从 CLI 设置。
@Kunok 它没有。这是开发的快速解决方案,但您仍然需要为生产解决一些问题。
contentBase :':/' 导致您的应用程序文件可以从 url 访问
适用于 React 17。谢谢
P
Peter Mortensen

对于 React Router V4 用户:

如果您尝试通过其他答案中提到的哈希历史技术解决此问题,请注意

<Router history={hashHistory} >

在 V4 中不起作用。请改用 HashRouter

import { HashRouter } from 'react-router-dom'

<HashRouter>
  <App/>
</HashRouter>

参考:HashRouter


您能否详细说明 HashRouter 解决此问题的原因?您提供的链接没有为我解释。另外,有没有办法隐藏路径中的哈希?我正在使用 BrowserRouter 但遇到了这个 404 问题..
我正在使用浏览器路由器,它在刷新时导致 404 错误,但后来我用哈希路由器替换了浏览器路由器,但它不能正常工作。谢谢
非常感谢你的朋友,我真的很感激。你为我节省了几个工作时间👍
不想在我的网址中使用哈希
P
Peter Mortensen

我刚才使用 Create React App 制作了一个网站,在这里遇到了同样的问题。

我使用 react-router-dom 包中的 BrowserRouting。我在 Nginx 服务器上运行并将以下内容添加到 /etc/nginx/yourconfig.conf 为我解决了这个问题:

location / {
  if (!-e $request_filename){
    rewrite ^(.*)$ /index.html break;
  }
}

如果您正在运行 Apache,则对应于将以下内容添加到 .htaccess

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

这似乎也是 Facebook 自己建议的解决方案,可以找到here


哇,这么简单的 nginx 解决方案;作为一个新的 nginx 用户,它就像一个魅力。只需复制粘贴即可。 +1 用于链接到官方 fb 文档。好样的。
作为记录:我正在使用带有 nginx 和 Angular 应用程序的 AWS 实例。这行得通。
你救我。我试图从昨天开始解决我的问题,我厌倦了几个解决方案,但我失败了。最后你帮我解决了这个路由器问题。啊 非常感谢兄弟
“react”:“^16.8.6”,“react-router”:“^5.0.1”有什么不同吗?我尝试了这些解决方案(nginx 和 apache),但它们不起作用。
由于 Facebook 没有更改有关此的文档,我只能假设程序是相同的。不过我有一段时间没试过了。
P
Peter Mortensen

在您的 index.html 文件的 head 中,添加以下内容:

<base href="/">
<!-- This must come before the CSS and JavaScript code -->

然后,在使用 Webpack 开发服务器运行时,使用此命令。

webpack-dev-server --mode development --hot --inline --content-base=dist --history-api-fallback

--history-api-fallback 是重要的部分


值得一提的是,如果您使用不是 / 的基本 href,那么 HashRouter 将不起作用(如果您使用的是哈希路由)
标签为我做了这件事。谢谢你。 Webpack 开发服务器不断尝试从路径/ 中获取包,但失败了。
我正在使用 React.js + Webpack 模式。我在 package.json 文件中添加了 --history-api-fallback 参数。然后页面刷新工作正常。每次更改代码时,网页都会自动刷新。 ``` "scripts": { "start": "rimraf build && cross-env NODE_ENV='development' webpack --mode development && cross-env NODE_ENV=development webpack-dev-server --history-api-fallback", ... } ```
拯救了这一天
P
Peter Mortensen

可以通过两种不同的方式调用路由器,具体取决于导航发生在客户端还是服务器上。您已将其配置为客户端操作。关键参数是 run method 的第二个参数,即位置。

当您使用 React Router Link 组件时,它会阻止浏览器导航并调用 transitionTo 来进行客户端导航。您正在使用 HistoryLocation,因此它使用 HTML5 历史 API 通过模拟地址栏中的新 URL 来完成导航的错觉。如果您使用的是旧版浏览器,这将不起作用。您将需要使用 HashLocation 组件。

当你点击刷新时,你绕过了所有的 React 和 React Router 代码。服务器收到对 /joblist 的请求,它必须返回一些东西。在服务器上,您需要将请求的路径传递给 run 方法,以便它呈现正确的视图。您可以使用相同的路线图,但您可能需要对 Router.run 进行不同的调用。正如查尔斯指出的那样,您可以使用 URL 重写来处理这个问题。另一种选择是使用 Node.js 服务器来处理所有请求并将路径值作为位置参数传递。

例如,在 Express.js 中,它可能如下所示:

var app = express();

app.get('*', function (req, res) { // This wildcard method handles all requests

    Router.run(routes, req.path, function (Handler, state) {
        var element = React.createElement(Handler);
        var html = React.renderToString(element);
        res.render('main', { content: html });
    });
});

请注意,请求路径正在传递给 run。为此,您需要有一个服务器端视图引擎,您可以将呈现的 HTML 传递给该引擎。使用 renderToString 和在服务器上运行 React 时还有许多其他注意事项。一旦页面在服务器上呈现,当您的应用程序在客户端加载时,它将再次呈现,并根据需要更新服务器端呈现的 HTML。


对不起,请问您能否解释下一条语句“当您点击刷新时,您会绕过所有 React 和 React Router 代码”?为什么会这样?
React 路由器通常仅用于处理浏览器内的不同“路径”。有两种典型的方法可以做到这一点:旧式哈希路径和新式历史 API。浏览器刷新将发出服务器请求,这将绕过您的客户端反应路由器代码。您将需要处理服务器上的路径(但仅当您使用历史 API 时)。您可以为此使用反应路由器,但您需要执行类似于我上面描述的操作。
知道了。但是,如果服务器使用非 JS 语言(比如说 Java)怎么办?
抱歉……您的意思是您需要一个快速服务器来呈现“非 root”的路由?我首先感到惊讶的是,同构的定义并未在其概念中包含数据获取(如果您想在数据服务器端渲染视图,事情会非常复杂,尽管这将是一个明显的 SEO 需求——并且同构声称它)。现在我就像“WTF 反应”,说真的……如果我错了,请纠正我,ember/angular/backbone 是否需要服务器来渲染路由?我真的不明白这个臃肿的使用路线的要求
如果我的反应应用程序不是同构的,这是否意味着反应路由器中的刷新不起作用?
P
Peter Mortensen

如果您使用的是 Create React App:

您可以在 Create React App 页面上找到许多主要托管平台的解决方案,其中包含有关此问题的精彩演练here。例如,我将 React Router v4 和 Netlify 用于我的前端代码。只需将一个文件添加到我的公共文件夹(“_redirects”)和该文件中的一行代码:

/*  /index.html  200

现在,当我的网站进入浏览器或有人点击刷新时,我的网站会正确呈现诸如 mysite.com/pricing 之类的路径。


如果您使用 Apache HTTP Server,则 .htaccess 不起作用,请检查 apache 版本,因为在 version 2.3.9 and later 中,默认 AllowOverrideNone 尝试更改 AllowOverrideAllcheck this answer
P
Peter Mortensen

如果您通过 AWS Static S3 Hosting 和 CloudFront 托管 React 应用程序

此问题由 CloudFront 以 403 Access Denied 消息响应而出现,因为它希望 /some/other/path 存在于我的 S3 文件夹中,但该路径仅存在于内部在 React 的路由中使用 React Router

解决方案是设置分发错误页面规则。转到 CloudFront 设置并选择您的分配。接下来,转到“错误页面”选项卡。单击“创建自定义错误响应”并为 403 添加一个条目,因为这是我们得到的错误状态代码。

将响应页面路径设置为 /index.html 并将状态代码设置为 200。

最终结果让我惊讶于它的简单性。提供索引页面,但 URL 保留在浏览器中,因此一旦 React 应用程序加载,它会检测 URL 路径并导航到所需的路由。

Error Pages 403 Rule


这正是我所需要的。谢谢你。
所以..你所有的网址都有效,但返回状态码 403?这是不正确的。预期的状态代码应在 2xx 范围内。
@StijndeWitt 我不确定您是否理解正确。 CloudFront 将处理一切 - 客户端不会看到任何 403 状态代码。重新路由发生在服务器端,呈现索引页面,维护 url,并提供正确的路由作为结果。
感谢@th3morg。此设置是否也适用于多级路径?如果根级别的任何路径(例如域/注册、域/登录、域/)对我来说非常有用,但它不适用于多级路径,例如域/文档/
哦,你美丽的存在!需要将其设置为 404 响应,它就像一个魅力!
P
Peter Mortensen

如果您在 IIS 上托管您的 React 应用程序,只需添加一个 web.config 文件,其中包含:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.webServer>
        <httpErrors errorMode="Custom" existingResponse="Replace">
            <remove statusCode="404" subStatusCode="-1" />
            <error statusCode="404" path="/" responseMode="ExecuteURL" />
        </httpErrors>
    </system.webServer>
</configuration>

这将告诉 IIS 服务器将主页返回给客户端而不是 404 错误,并且不需要使用哈希历史记录。


这简单地解决了我们的问题,谢谢
P
Peter Mortensen

这可以解决您的问题。

我在生产模式下的 React 应用程序中也遇到了同样的问题。这是解决问题的两种方法。

解决方案1.将路由历史改为“hashHistory”而不是browserHistory代替

<Router history={hashHistory} >
   <Route path="/home" component={Home} />
   <Route path="/aboutus" component={AboutUs} />
</Router>

现在使用命令构建应用程序

sudo npm run build

然后将构建文件夹放在您的 var/www/ 文件夹中。现在,在每个 URL 中添加 # 标记后,应用程序运行良好。喜欢

localhost/#/home
localhost/#/aboutus

解决方案2:没有#标签使用browserHistory,

在您的路由器中设置您的历史记录 = {browserHistory}。现在使用 sudo npm run build 构建它。

您需要创建“conf”文件来解决 404 not found 页面。 conf文件应该是这样的。

打开终端输入以下命令

cd /etc/apache2/sites-available
ls
nano sample.conf

在其中添加以下内容。

<VirtualHost *:80>
    ServerAdmin admin@0.0.0.0
    ServerName 0.0.0.0
    ServerAlias 0.0.0.0
    DocumentRoot /var/www/html/

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    <Directory "/var/www/html/">
            Options Indexes FollowSymLinks
            AllowOverride all
            Require all granted
    </Directory>
</VirtualHost>

现在您需要使用以下命令启用 sample.conf 文件:

cd /etc/apache2/sites-available
sudo a2ensite sample.conf

然后它会要求你重新加载 Apache 服务器,使用

sudo service apache2 reload or restart

然后打开 localhost/build 文件夹并添加具有以下内容的 .htaccess 文件。

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^.*$ / [L,QSA]

现在该应用程序正常运行。

注意:将 0.0.0.0 IP 地址更改为您的本地 IP 地址。


第一个解决方案适用于 "react-router-dom": "^5.1.2" 吗?我正在使用 <BrowserRouter>
.htaccess 为我修复了它。
在哪里,我会在解决方案 2 中获得 browserHistory。
在为我修复的构建文件夹中仅添加 .htaccess 文件,谢谢
为什么会有人sudo build
S
Sebastian Kaczmarek

将此添加到 webpack.config.js

devServer: {
    historyApiFallback: true
}

这对开发人员来说很棒,但对生产构建没有帮助。
谢谢...确实将其固定在一行中
为我工作! 🔥
为什么它有效?解释是什么?它是在什么版本上测试的?
P
Peter Mortensen

Webpack 开发服务器有一个选项来启用它。打开 package.json 并添加 --history-api-fallback。这个解决方案对我有用。

react-router-tutorial


webpack-dev-server 没问题,但如何为生产版本解决这个问题?
P
Peter Mortensen

生产堆栈:React、React Router v4、BrowswerRouter、Express.js、Nginx

用于漂亮 URL 的用户 BrowserRouter 文件 app.js import { BrowserRouter as Router } from 'react-router-dom' const App = () { render() { return ( // 你的路由在这里 ) } }使用 /* File server.js app.get('/*', function(req, res) { res.sendFile(path.join(__dirname, 'path/to/your/index) 将 index.html 添加到所有未知请求.html'), function(err) { if (err) { res.status(500).send(err) } }) }) 将 Webpack 与 webpack 捆绑在一起 -p 运行 nodemon server.js 或 node server.js

您可能希望让 nginx 在服务器块中处理此问题并忽略第 2 步:

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

获取未定义的路径
@Goutham 在 server.js 文件的顶部添加 import path from 'pathconst path = require('path')
第 2 步(使用 /* 了解所有内容)刚刚拯救了我的一天。谢谢! :)
这很有效,对于使用 redux 并关心连接路由器的人来说,请参阅以下示例:github.com/supasate/connected-react-router/tree/master/examples/…
P
Peter Mortensen

尝试使用以下代码在公用文件夹中添加“.htaccess”文件。

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

RewriteRule ^ /index.html [L]

谢谢,这对我在 Fedora 28 和 apache 上有用。上述重写规则和 CRA 页面上的规则都不适合我。我将它们添加到虚拟主机设置中,而不是在单独的 .htaccess 文件中。
P
Peter Mortensen

如果您使用 nginx 进行托管并需要快速修复...

将以下行添加到 location 块内的 nginx 配置中:

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

P
Peter Mortensen

如果您使用的是 Firebase,您所要做的就是确保您的应用根目录中的 firebase.json 文件中有一个 rewrites 属性(在托管部分中)。

例如:

{
  "hosting": {
    "rewrites": [{
      "source":"**",
      "destination": "/index.html"
    }]
  }
}

关于该主题的进一步阅读:

配置重写

Firebase CLI:“配置为单页应用(将所有 url 重写为 /index.html)”


你是个传奇
太感谢了。很棒的解决方案!
P
Peter Mortensen

对于使用 IIS 10 的用户,您应该这样做以使其正确。

确保您使用的是 browserHistory 。至于参考,我会给出路由的代码,但这并不重要。重要的是下面的组件代码之后的下一步:

class App extends Component {
    render() {
        return (
            <Router history={browserHistory}>
                <div>
                    <Root>
                        <Switch>
                            <Route exact path={"/"} component={Home} />
                            <Route path={"/home"} component={Home} />
                            <Route path={"/createnewproject"} component={CreateNewProject} />
                            <Route path={"/projects"} component={Projects} />
                            <Route path="*" component={NotFoundRoute} />
                        </Switch>
                    </Root>
                </div>
            </Router>
        )
    }
}
render (<App />, window.document.getElementById("app"));

由于问题是 IIS 接收来自客户端浏览器的请求,它会将 URL 解释为请求页面,然后返回 404 页面,因为没有任何可用页面。请执行下列操作:

打开 IIS 展开服务器,然后打开站点文件夹单击网站/应用程序转到错误页面打开列表中的 404 错误状态项而不是选项“将静态文件中的内容插入错误响应”,将其更改为“在此站点上执行 URL”并将“/”斜杠值添加到 URL。

现在它可以正常工作了。

https://i.stack.imgur.com/sihHh.png

https://i.stack.imgur.com/12o6e.png


搜索 3-4 小时后的最佳解决方案。多谢 :)
M
Matt Goo

如果您确实有对 index.html 的后备,请确保在您的 index.html 文件中有以下内容:

<script>
  System.config({ baseURL: '/' });
</script>

这可能因项目而异。


将此添加到您的 html head:<base href="/">
这对我有用,谢谢(将 '' 添加到 index.html 头)
P
Peter Mortensen

如果您在后端使用 Express.js 或其他一些框架,您可以添加如下类似的配置,并在配置中查看 Webpack 公共路径。如果您使用的是 BrowserRouter,即使重新加载它也应该可以正常工作。

expressApp.get('/*', (request, response) => {
    response.sendFile(path.join(__dirname, '../public/index.html'));
});

这是最简单的解决方案。请注意,这条路线应该遵循任何其他路线,因为它是一个包罗万象的路线
从“”更改为“/”为我解决了类似的问题。但是,浏览器在刷新或 URL 导航时收到了一个空的 HTML,而不是作为 OP 收到错误“无法获取”。
P
Peter Mortensen

我使用 React Router (Apache) 为我的 SPA 找到了解决方案。只需将其添加到文件 .htaccess 中:

<IfModule mod_rewrite.c>

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

</IfModule>

来源:Apache configuration for React Router


r
ravibagul91

修复刷新或直接调用 URL 时出现的“无法获取 /URL”错误。

配置你的 webpack.config.js 以期望给定的链接像这样的路由。

module.exports = {
  entry: './app/index.js',
  output: {
       path: path.join(__dirname, '/bundle'),
       filename: 'index_bundle.js',
       publicPath: '/'
  },

这个解决方案是我在这里找到的最简单、最有效的解决方案。非常感谢!
P
Peter Mortensen

如果您使用的是“create-react-app”命令,

要生成 React 应用程序,则 package.json 文件需要进行一次更改,以便在浏览器中正确运行生产构建 React SPA。打开文件 package.json 并添加以下代码段,

"start": "webpack-dev-server --inline --content-base . --history-api-fallback"

这里最重要的部分是启用历史 API 回调的“--history-api-fallback”。

如果您使用 Spring 或任何其他后端 API,有时您会收到 404 错误。因此在这种情况下,您需要在后端有一个控制器来将任何请求(您想要的)转发到 index.html 文件以由 react-router 处理。下面演示了一个使用 Spring 编写的示例控制器。

@Controller
public class ForwardingController {
    @RequestMapping("/<any end point name>/{path:[^\\.]+}/**")
    public String forward(HttpServletRequest httpServletRequest) {
        return "forward:/";
    }
}

例如,如果我们将后端 API REST 端点作为“abc”(http://localhost:8080/abc/**),那么任何到达该端点的请求都将重定向到 React 应用程序 ( index.html 文件),然后 react-router 将处理它。


您还可以像这样添加多个映射:@RequestMapping({"/myurl1/**", "/myurl2/**"})
P
Peter Mortensen

Redux 中使用 HashRouter 也对我有用。只需简单地替换:

import {
    Router //replace Router
} from "react-router-dom";

ReactDOM.render(
    <LocaleProvider locale={enUS}>
        <Provider store={Store}>
            <Router history={history}> // Replace here saying Router
                <Layout/>
            </Router>
        </Provider>
    </LocaleProvider>, document.getElementById("app"));

registerServiceWorker();

和:

import {
    HashRouter // Replaced with HashRouter
} from "react-router-dom";

ReactDOM.render(
    <LocaleProvider locale={enUS}>
        <Provider store={Store}>
            <HashRouter history={history}> //replaced with HashRouter
                <Layout/>
            </HashRouter>
        </Provider>
    </LocaleProvider>, document.getElementById("app"));

registerServiceWorker();

“ReactDOM”的语法高亮很奇怪。
P
Peter Mortensen

这是一个简单,清晰和更好的解决方案。如果您使用网络服务器,它就可以工作。

每个 Web 服务器都可以在 HTTP 404 的情况下将用户重定向到错误页面。要解决此问题,您需要将用户重定向到索引页面。

如果您使用 Java 基础服务器(Tomcat 或任何 Java 应用程序服务器),解决方案可能如下:

网页.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- WELCOME FILE LIST -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- ERROR PAGES DEFINITION -->
    <error-page>
        <error-code>404</error-code>
        <location>/index.jsp</location>
    </error-page>

</web-app>

例子:

获取 http://example.com/about

Web 服务器抛出 HTTP 404,因为该页面在服务器端不存在

错误页面配置告诉服务器将 index.jsp 页面发送回用户

然后 JavaScript 将在客户端完成剩下的工作,因为客户端的 URL 仍然是 http://example.com/about。

这就对了。不再需要魔法:)


这太棒了!我正在使用 Wildfly 10.1 服务器并对我的 web.xml 文件进行了此更新,但我将位置设置为“/”。这是因为在我的反应代码中,我使用了这样的浏览器历史记录:const browserHistory = useRouterHistory(createHistory)({ basename: '/<appname>' });
您确定这不会影响 SEO 吗?您正在为实际存在的页面提供 404 状态。用户可能永远不会意识到这一点,但机器人确实非常关注,事实上,他们不会抓取您的页面。
P
Peter Mortensen

我通过更改文件 webpack.config.js 解决了这个问题。

我的新配置如下所示:

output: {
  path: path.join(__dirname, '/build/static/js'),
  filename: 'index.js'
},


devServer: {
  port: 3000
}

output: {
  path: path.join(__dirname, '/build/static/js'),
  filename: 'index.js',
  publicPath: '/'
},


devServer: {
  historyApiFallback: true,
  port: 3000
}

P
Peter Mortensen

我还没有使用服务器端渲染,但是我遇到了与 OP 相同的问题,其中 Link 似乎在大多数情况下都可以正常工作,但是当我有一个参数时却失败了。我将在这里记录我的解决方案,看看它是否对任何人有帮助。

我的主要 JSX 内容包含以下内容:

<Route onEnter={requireLogin} path="detail/:id" component={ModelDetail} />

这适用于第一个匹配的链接,但是当嵌套在该模型的详细信息页面上的 <Link> 表达式中的 :id 更改时,浏览器栏中的 URL 会更改,但页面的内容最初并未更改以反映链接的模型.

问题是我使用 props.params.id 将模型设置在 componentDidMount 中。该组件仅安装一次,因此这意味着第一个模型是粘贴在页面上的模型,随后的链接更改了道具,但页面看起来没有变化。

componentDidMountcomponentWillReceiveProps(它基于下一个道具)中将模型设置为组件状态可以解决问题,并且页面内容会更改以反映所需的模型。


如果您想尝试服务器端呈现,最好使用组件构造函数(也可以访问 props)iso componentDidMount。因为 componentDidMount 只在浏览器中被调用。它的目的是用 DOM 做一些事情,例如将事件侦听器附加到 body 等,而这在 render 中是无法做到的。
A
Agney

Joshua Dyck's answer 添加更多信息。

如果您使用 Firebase 并希望同时使用根路由和子目录路由,则需要在 firebase.json 中添加以下代码:

{
  "hosting": {
    "rewrites": [
      {
        "source": "*",
        "destination": "/index.html"
      },
      {
        "source": "/subdirectory/**",
        "destination": "/subdirectory/index.html"
      }
    ]
  }
}

例子:

您正在为客户建立网站。您希望网站所有者在 https://your.domain.com/management 中添加信息,而网站用户将导航到 https://your.domain.com

在这种情况下,您的 firebase.json 文件将如下所示:

{
  "hosting": {
    "rewrites": [
      {
        "source": "*",
        "destination": "/index.html"
      },
      {
        "source": "/management/**",
        "destination": "/management/index.html"
      }
    ]
  }
}

D
Dušan

我正在使用 ASP.NET CoreReact。生产环境中手动路由和刷新路由问题的解决方案是在 ASP.NET Core 主项目的根目录下创建 web.config 文件,该文件将在生产服务器上配置路由。

项目中文件的位置:

https://i.stack.imgur.com/SBc06.png

web.config 文件的内容:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="Rewrite Text Requests" stopProcessing="true">
                    <match url=".*" />
                    <conditions>
                        <add input="{HTTP_METHOD}" pattern="^GET$" />
                        <add input="{HTTP_ACCEPT}" pattern="^text/html" />
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/index.html" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

P
Peter Mortensen

如果您在 IIS 中托管:将此添加到我的 webconfig 解决了我的问题

<httpErrors errorMode="Custom" defaultResponseMode="ExecuteURL">
    <remove statusCode="500" subStatusCode="100" />
    <remove statusCode="500" subStatusCode="-1" />
    <remove statusCode="404" subStatusCode="-1" />
    <error statusCode="404" path="/" responseMode="ExecuteURL" />
    <error statusCode="500" prefixLanguageFilePath="" path="/error_500.asp" responseMode="ExecuteURL" />
    <error statusCode="500" subStatusCode="100" path="/error_500.asp" responseMode="ExecuteURL" />
</httpErrors>

您可以为任何其他服务器进行类似的配置。