手动刷新或写入时,React-router url 不起作用
Posted
技术标签:
【中文标题】手动刷新或写入时,React-router url 不起作用【英文标题】:React-router urls don't work when refreshing or writing manually 【发布时间】:2021-05-16 12:02:37 【问题描述】:我正在使用 React-router,当我点击链接按钮时它工作正常,但是当我刷新我的网页时它没有加载我想要的。
例如,我在localhost/joblist
,一切都很好,因为我按链接到达这里。但如果我刷新网页,我会得到:
Cannot GET /joblist
默认情况下,它不是这样工作的。最初,我的 URL 为 localhost/#/
和 localhost/#/joblist
,它们运行良好。但我不喜欢这种网址,所以想抹掉那个#
,我写道:
Router.run(routes, Router.HistoryLocation, function (Handler)
React.render(<Handler/>, document.body);
);
localhost/
不会出现这个问题,这个总是返回我想要的。
编辑:这个应用程序是单页的,所以/joblist
不需要向任何服务器询问任何内容。
EDIT2:我的整个路由器。
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/…
【参考方案1】:
可以通过两种不同的方式调用路由器,具体取决于导航发生在客户端还是服务器上。您已将其配置为客户端操作。关键参数是run method 的第二个参数,位置。
当您使用 React Router Link 组件时,它会阻止浏览器导航并调用 transitionTo 来进行客户端导航。您正在使用 HistoryLocation,因此它使用 HTML5 历史 API 通过模拟地址栏中的新 URL 来完成导航的错觉。如果您使用的是旧版浏览器,这将不起作用。您需要使用 HashLocation 组件。
当您点击刷新时,您会绕过所有 React 和 React Router 代码。服务器收到/joblist
的请求,它必须返回一些东西。在服务器上,您需要将请求的路径传递给 run
方法,以便它呈现正确的视图。您可以使用相同的路线图,但您可能需要对Router.run
进行不同的调用。正如查尔斯指出的那样,您可以使用 URL 重写来处理这个问题。另一种选择是使用 node.js 服务器来处理所有请求并将路径值作为位置参数传递。
例如,在 express 中,它可能看起来像这样:
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。
【讨论】:
excuse 对不起,请您解释一下下一条语句“当您点击刷新时,您会绕过所有 React 和 React Router 代码”?为什么会这样? React 路由器通常仅用于处理浏览器中的不同“路径”。有两种典型的方法可以做到这一点:旧式哈希路径和新式历史 API。浏览器刷新将发出服务器请求,这将绕过您的客户端反应路由器代码。您将需要处理服务器上的路径(但仅当您使用历史 API 时)。您可以为此使用反应路由器,但您需要执行类似于我上面描述的操作。 知道了。但是如果服务器使用非 JS 语言(比如说 Java)怎么办? 对不起……你的意思是你需要一个快速服务器来呈现一个“非根”的路由?我首先感到惊讶的是,同构的定义并未在其概念中包含数据获取(如果您想在数据服务器端渲染视图,事情会非常复杂,尽管这将是一个明显的 SEO 需求——并且同构声称它)。现在我就像“WTF 反应”,说真的……如果我错了,请纠正我,ember/angular/backbone 是否需要服务器来渲染路由?我真的不明白这种使用路由的臃肿要求 如果我的 react 应用程序不是同构的,是否意味着 react-router 中的刷新不起作用?【参考方案2】:查看已接受答案的 cmets 和此问题的一般性质(“不工作”),我认为这可能是对此处涉及的问题进行一些一般性解释的好地方。因此,此答案旨在作为 OP 特定用例的背景信息/详细说明。请多多包涵。
服务器端与客户端
首先要了解的是,现在有 2 个位置可以解释 URL,而过去只有 1 个。过去,当生活很简单的时候,一些用户向服务器发送http://example.com/about
的请求,服务器检查 URL 的路径部分,确定用户正在请求关于页面,然后发回该页面。
使用 React-Router 提供的客户端路由,事情就不那么简单了。起初,客户端还没有加载任何 JS 代码。所以第一个请求将永远是服务器。然后将返回一个页面,其中包含加载 React 和 React Router 等所需的脚本标签。只有当这些脚本加载后,阶段 2 才会开始。例如,在第 2 阶段,当用户单击“关于我们”导航链接时,URL 仅在本地更改为 http://example.com/about
(通过 History API 实现),但 没有向服务器发出请求。相反,React Router 在客户端做它的事情,决定渲染哪个 React 视图,然后渲染它。假设您的关于页面不需要进行任何 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 的包罗万象的路由,到服务器和客户端都运行相同的 JS 代码的全面同构方法。
.
完全绕过问题:哈希历史
使用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 作为我们的服务器,那么我们可以在两端运行相同的 JS 代码会怎样?现在,我们在一个 react-router 配置中定义了所有路由,我们不需要复制渲染代码。这就是所谓的“圣杯”。如果页面转换发生在客户端,服务器会发送与我们最终发送的完全相同的标记。该解决方案在 SEO 方面是最佳的。
缺点:
服务器必须(能够)运行 JS。我已经尝试过 Java i.c.w。 Nashorn,但它对我不起作用。在实践中,这主要意味着您必须使用基于 Node JS 的服务器。 许多棘手的环境问题(在服务器端使用window
等)
陡峭的学习曲线
.
我应该使用哪个?
选择一个你可以逃脱的。就个人而言,我认为包罗万象很容易设置,所以这将是我的最低要求。此设置允许您随着时间的推移改进事物。如果您已经在使用 Node JS 作为服务器平台,我肯定会研究做一个同构应用程序。是的,一开始很难,但一旦你掌握了窍门,它实际上是解决问题的一个非常优雅的解决方案。
所以基本上,对我来说,这将是决定因素。如果我的服务器在 Node JS 上运行,我会采用同构的;否则,我会选择 Catch-all 解决方案,并随着时间的推移和 SEO 需求的需要对其进行扩展(混合解决方案)。
如果您想了解更多关于使用 React 进行同构(也称为“通用”)渲染的信息,这里有一些很好的教程:
React to the future with isomorphic apps The Pain and the Joy of creating isomorphic apps in ReactJS How to Implement Node + React Isomorphic JavaScript & Why it Matters另外,为了让您入门,我建议您查看一些入门工具包。选择一个与你的技术栈选择相匹配的技术栈(记住,React 只是 MVC 中的 V,你需要更多的东西来构建一个完整的应用程序)。先看看 Facebook 自己发布的:
Create React App或者从社区中选择一个。现在有一个不错的网站尝试将所有这些都编入索引:
Pick your perfect React starter project我从这些开始:
React Isomorphic Starterkit React Redux Universal Hot Example目前,我正在使用受上述两个入门套件启发的自制版本的通用渲染,但它们现在已经过时了。
祝你任务顺利!
【讨论】:
很棒的 Stijn 帖子!你会推荐使用同构反应应用程序的入门工具包吗?如果是这样,你能举一个你喜欢的例子吗? @Paulos3000 这取决于您使用的服务器。基本上,您为/*
定义一个路由,并使其响应您的HTML 页面。这里的棘手之处在于确保您不会使用此路由拦截对 .js 和 .css 文件的请求。
@Paulos3000 相关问题请参见此处:for Apache/php、for Express/js、for J2E/Java。
@Stijn de Witt 这是一个很好的澄清,并在这个主题上得到了很好的回答。但是,当您的应用程序可以在子目录中提供时(例如通过 iis),有哪些选项。即:domain/appName/routeName 或 domain/appName/subfolder/routeName
@LeonGaban 似乎自从写了这个答案以来,React Router 改变了他们的实现。他们现在有不同的路由器实例用于不同的历史记录,并且他们在后台配置历史记录。基本原理还是一样的。【参考方案3】:
如果您确实有 index.html 的后备,请确保在您的 index.html 文件中有以下内容:
<script>
System.config( baseURL: '/' );
</script>
这可能因项目而异。
【讨论】:
将此添加到您的 htmlhead
: 这里的答案都非常有帮助,对我有用的是将我的 Webpack 服务器配置为期望路由。
devServer:
historyApiFallback: true,
contentBase: './',
hot: true
,
historyApiFallback 为我解决了这个问题。现在路由工作正常,我可以刷新页面或直接输入 URL。无需担心节点服务器上的变通方法。这个答案显然只有在您使用 webpack 时才有效。
编辑:请在此处查看我的答案,了解为什么这是必要的更详细的原因: https://***.com/a/37622953/5217568
【讨论】:
请注意,Webpack 团队 recommends against 在生产中使用开发服务器。 对于通用开发目的,这是最好的解决方案。historyApiFallback
就足够了。至于所有其他选项,也可以从 CLI 使用标志 --history-api-fallback
进行设置。
@Kunok 它没有。这是开发的快速解决方案,但您仍然需要为生产解决问题。
contentBase :':/' 因为你的应用文件可以从 url 访问
适用于 React 17。谢谢【参考方案5】:
Webpack 开发服务器有一个选项可以启用它。打开package.json
并添加--history-api-fallback
。
这个解决方案对我有用。
react-router-tutorial
【讨论】:
webpack-dev-server
没问题,但我如何为生产版本解决这个问题?【参考方案6】:
我还没有使用服务器端渲染,但我遇到了与 OP 相同的问题,其中 Link 似乎大部分时间都可以正常工作,但当我有参数时却失败了。我将在这里记录我的解决方案,看看它是否对任何人都有帮助。
我的主要 jsx 包含这个:
<Route onEnter=requireLogin path="detail/:id" component=ModelDetail />
这适用于第一个匹配链接,但是当嵌套在该模型的详细信息页面上的 <Link>
表达式中的 :id 更改时,浏览器栏中的 url 会更改,但页面的内容最初并未更改以反映链接型号。
问题是我使用props.params.id
将模型设置为componentDidMount
。该组件仅安装一次,因此这意味着第一个模型是粘贴在页面上的模型,随后的链接会更改道具但保持页面外观不变。
在componentDidMount
和componentWillReceiveProps
(它基于下一个道具)中将模型设置为组件状态可以解决问题,并且页面内容会更改以反映所需的模型。
【讨论】:
最好使用组件构造函数(也可以访问props
)i.s.o。 componentDidMount
如果您想尝试服务器端渲染。因为componentDidMount
只在浏览器中被调用。它的目的是用 DOM 做一些事情,例如将事件侦听器附加到 body
等你在 render
中无法做到的事情。【参考方案7】:
您可以更改您的 .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
之后的路径与应用程序所在的文件夹匹配(如果它是子文件夹)【参考方案8】:
这个话题有点老了,已经解决了,但我想建议你一个简单、清晰和更好的解决方案。如果你使用网络服务器,它就可以工作。
每个 Web 服务器都可以在 http 404 的情况下将用户重定向到错误页面。要解决此问题,您需要将用户重定向到索引页面。
如果您使用 Java 基础服务器(tomcat 或任何 Java 应用程序服务器),解决方案可能如下:
web.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 页面发回给用户 那么 JS 将在客户端完成剩下的工作,因为客户端的 url 仍然是http://example.com/about。就是这样,不再需要魔法了:)
【讨论】:
这太棒了!我正在使用 Wildfly 10.1 服务器并对我的 web.xml 文件进行了此更新,但我将位置设置为“/”。这是因为在我的反应代码中,我使用了这样的浏览器历史记录:const browserHistory = useRouterHistory(createHistory)( basename: '/<appname>' );
您确定这不会影响 SEO 吗?您正在为实际存在的页面提供 404 状态。用户可能永远不会意识到这一点,但机器人确实会非常关注,事实上非常关注,以至于它们不会抓取您的页面。【参考方案9】:
这可以解决你的问题
我在生产模式下的 ReactJS 应用程序中也遇到了同样的问题。 这是问题的2个解决方案。
1.将路由历史改为“hashHistory”而不是browserHistory代替
<Router history=hashHistory >
<Route path="/home" component=Home />
<Route path="/aboutus" component=AboutUs />
</Router>
现在使用命令构建应用程序
sudo npm run build
然后将 build 文件夹放在您的 var/www/ 文件夹中,现在应用程序可以正常工作,并在每个 URL 中添加 # 标记。喜欢
本地主机/#/home 本地主机/#/关于我们
解决方案2:不使用#标签使用browserHistory,
在你的路由器中设置你的 history = browserHistory,现在使用 sudo npm run build 构建它。
你需要创建“conf”文件来解决404 not found页面, conf文件应该是这样的。
打开终端输入以下命令
cd /etc/apache2/sites-available ls 纳米样本.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 重新加载或重启
然后打开您的 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
?【参考方案10】:
对于 React Router V4 用户:
如果您尝试通过其他答案中提到的哈希历史技术解决此问题,请注意
<Router history=hashHistory >
在 V4 中不起作用,请改用HashRouter
:
import HashRouter from 'react-router-dom'
<HashRouter>
<App/>
</HashRouter>
参考:HashRouter
【讨论】:
您能否详细说明 HashRouter 解决此问题的原因?您提供的链接没有为我解释。另外,有没有办法隐藏路径中的哈希?我正在使用 BrowserRouter,但遇到了这个 404 问题.. 我正在使用浏览器路由器,刷新时导致 404 错误,但后来我用哈希路由器替换了浏览器路由器,但它不能正常工作。谢谢【参考方案11】:如果您在 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>
您可以为任何其他服务器进行类似的配置
【讨论】:
【参考方案12】:我遇到了同样的问题,this 解决方案对我们有用..
背景:
我们在同一台服务器上托管多个应用程序。当我们刷新服务器时,服务器将不知道在 dist 文件夹中为该特定应用程序查找索引的位置。上面的链接将带您了解对我们有用的内容......希望这会有所帮助,因为我们已经花费了相当多的时间来找出满足我们需求的解决方案。
我们正在使用:
package.json
"dependencies":
"babel-polyfill": "^6.23.0",
"ejs": "^2.5.6",
"express": "^4.15.2",
"prop-types": "^15.5.6",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.4",
"react-router": "^3.0.2",
"react-router-redux": "^4.0.8",
"redux": "^3.6.0",
"redux-persist": "^4.6.0",
"redux-thunk": "^2.2.0",
"webpack": "^2.4.1"
我的 webpack.config.js
webpack.config.js
/* eslint-disable */
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const babelPolyfill = require('babel-polyfill');
const HTMLWebpackPluginConfig = new HtmlWebpackPlugin(
template: __dirname + '/app/views/index.html',
filename: 'index.html',
inject: 'body'
);
module.exports =
entry: [
'babel-polyfill', './app/index.js'
],
output:
path: __dirname + '/dist/your_app_name_here',
filename: 'index_bundle.js'
,
module:
rules: [
test: /\.js$/,
loader: 'babel-loader',
query :
presets : ["env", "react", "stage-1"]
,
exclude: /node_modules/
]
,
plugins: [HTMLWebpackPluginConfig]
我的 index.js
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import Routes from './Routes'
import Provider from 'react-redux'
import createHistory from 'history'
import useRouterHistory from 'react-router'
import configureStore from './store/configureStore'
import syncHistoryWithStore from 'react-router-redux'
import persistStore from 'redux-persist'
const store = configureStore();
const browserHistory = useRouterHistory(createHistory) (
basename: '/your_app_name_here'
)
const history = syncHistoryWithStore(browserHistory, store)
persistStore(store, blacklist: ['routing'], () =>
console.log('rehydration complete')
)
// persistStore(store).purge()
ReactDOM.render(
<Provider store=store>
<div>
<Routes history=history />
</div>
</Provider>,
document.getElementById('mount')
)
我的 app.js
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/dist'));
// app.use(express.static(__dirname + '/app/assets'));
app.set('views', __dirname + '/dist/your_app_name_here');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.get('/*', function (req, res)
res.render('index');
);
app.listen(8081, function ()
console.log('MD listening on port 8081!');
);
【讨论】:
【参考方案13】:如果您使用的是 Create React App:
您可以在 Create React App 页面上找到 HERE 的许多主要托管平台的解决方案来解决这个问题。例如,我将 React Router v4 和 Netlify 用于我的前端代码。只需将 1 个文件添加到我的公共文件夹(“_redirects”)和该文件中的一行代码:
/* /index.html 200
现在,当我的网站进入浏览器或有人点击刷新时,我的网站会正确呈现诸如 mysite.com/pricing 之类的路径。
【讨论】:
如果您使用Apache HTTP Server,那么.htaccess 不起作用,请检查apache 版本,因为在version 2.3.9 and later 中默认的AllowOverride 是None 尝试将 AllowOverride 更改为 All。 check this answer【参考方案14】:生产堆栈:React、React Router v4、BrowswerRouter、Express、Nginx
1) 用于漂亮 url 的用户 BrowserRouter
// app.js
import BrowserRouter as Router from 'react-router-dom'
const App = ()
render()
return (
<Router>
// your routes here
</Router>
)
2) 使用/*
将 index.html 添加到所有未知请求中
// server.js
app.get('/*', function(req, res)
res.sendFile(path.join(__dirname, 'path/to/your/index.html'), function(err)
if (err)
res.status(500).send(err)
)
)
3) 将 webpack 与 webpack -p
捆绑在一起
4) 运行 nodemon server.js
或 node server.js
编辑:您可能希望让 nginx 在服务器块中处理此问题并忽略第 2 步:
location /
try_files $uri /index.html;
【讨论】:
获取未定义的路径 @Goutham 在 server.js 文件的顶部添加import path from 'path
或 const path = require('path')
第 2 步(使用 /*
了解所有内容)刚刚拯救了我的一天。谢谢! :)
这很有效,对于使用 redux 和关心连接路由器的人来说,请参见这个例子:github.com/supasate/connected-react-router/tree/master/examples/…【参考方案15】:
我刚刚使用 create-react-app 制作了一个网站,并且在这里遇到了同样的问题。我使用react-router-dom
包中的BrowserRouting
。我在 Nginx 服务器上运行,为我解决的问题是将以下内容添加到 /etc/nginx/yourconfig.conf
location /
if (!-e $request_filename)
rewrite ^(.*)$ /index.html break;
如果您正在运行 Appache,则对应于将以下内容添加到 .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 没有更改其关于此的文档,我只能假设程序是相同的。不过我有一段时间没试过了。【参考方案16】:将此添加到webpack.config.js
:
devServer:
historyApiFallback: true
【讨论】:
这对开发人员来说很棒,但对生产构建没有帮助。 谢谢你... 真的把它修好了 为我工作! ?【参考方案17】:使用 preact-router 的 Preact 解决方案
适用于刷新和直接访问
对于那些通过 Google 发现这一点的人,这里有一个 preact-router + 哈希历史的演示:
const h, Component, render = preact; /** @jsx h */
const Router = preactRouter;
const createHashHistory = History;
const App = () => (
<div>
<AddressBar />
<Router history=createHashHistory()>
<div path="/">
<p>
all paths in preact-router are still /normal/urls.
using hash history rewrites them to /#/hash/urls
</p>
Example: <a href="/page2">page 2</a>
</div>
<div path="/page2">
<p>Page Two</p>
<a href="/">back to home</a><br/>
</div>
</Router>
</div>
);
jsfiddle
【讨论】:
【参考方案18】:如果您在 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 错误,并且不需要使用哈希历史记录。
【讨论】:
这简单解决了我们的问题,谢谢【参考方案19】:如果有人在这里使用 Laravel 寻找 React JS SPA 的解决方案。
公认的答案是对为什么会发生此类问题的最佳解释。如前所述,您必须同时配置客户端和服务器端。
在你的刀片模板中,包含 js 捆绑文件,确保像这样使用URL facade
<script src=" URL::to('js/user/spa.js') "></script>
在您的路由中,确保将其添加到刀片模板所在的主端点。例如,
Route::get('/setting-alerts', function ()
return view('user.set-alerts');
);
以上是刀片模板的主要端点。现在也添加一条可选路线,
Route::get('/setting-alerts/spa?', function ()
return view('user.set-alerts');
);
发生的问题是首先加载刀片模板,然后是反应路由器。因此,当您加载 '/setting-alerts'
时,它会加载 html 和 js。但是当你加载'/setting-alerts/about'
时,它首先加载到服务器端。由于在服务器端,此位置没有任何内容,因此返回未找到。当你有那个可选的路由器时,它会加载同一个页面并且反应路由器也被加载,然后反应加载器决定显示哪个组件。
希望这会有所帮助。
【讨论】:
是否可以将一个确切的 URI 加载到服务器然后服务器重定向到 React?例如,当我加载/user/userID
时,我只需要返回一个通用的/user
HTML 视图,带上 ID 并使用 AJAX 或 axios 调用它。有可能这样做吗?他们对 SEO 友好吗?
我将此代码用于我的带有 Laravel 后端的 SPA:Route::any('any?', 'MyController@index');
它匹配任何路由并将其传递给 SPA【参考方案20】:
如果您通过 AWS 静态 S3 托管和 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。此设置是否也适用于多级路径?如果根级别的任何路径(例如域/注册、域/登录、域/当您在刷新 dom 组件后出现无法获得 403 错误时,这非常简单。只需在你的 webpack 配置中添加这一行,'historyApiFallback: true'。这节省了我一整天的时间。
【讨论】:
【参考方案22】:如果您在后端使用 Express 或其他框架,您可以添加如下类似的配置并检查配置中的 Webpack 公共路径,如果您使用的是 BrowserRouter,即使重新加载也应该可以正常工作
expressApp.get('/*', (request, response) =>
response.sendFile(path.join(__dirname, '../public/index.html'));
);
【讨论】:
这是最简单的解决方案。请注意,这条路线应该在任何其他路线之后走,因为它是一个全面的路线 从“”更改为“/”为我解决了类似的问题。但是,浏览器在刷新或 URL 导航时收到了一个空的 HTML,而不是作为 OP 收到错误“无法 GET”。【参考方案23】:在您的 index.html head
中,添加以下内容:
<base href="/">
<!-- This must come before the css and javascripts -->
然后在使用 webpack 开发服务器运行时使用此命令。
webpack-dev-server --mode development --hot --inline --content-base=dist --history-api-fallback
--history-api-fallback
是重要的部分
【讨论】:
这很棒!是否有任何链接可以详细了解您如何获得/找到该解决方案? 对不起,兄弟。通过反复试验的可靠技术找到它。 值得一提的是,如果您使用不是/
的基本href,那么HashRouter
将不起作用(如果您使用的是哈希路由)
对于那些使用 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 中添加“/”斜杠值。
它现在可以正常工作了。
我希望它有所帮助。 :-)
【讨论】:
搜索 3-4 小时后的最佳解决方案。非常感谢:)【参考方案25】:尝试使用以下代码在公用文件夹中添加“.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 文件中。【参考方案26】:如果您使用的是 firebase,您所要做的就是确保您的应用根目录下的 firebase.json 文件中有一个 rewrites 属性(在托管部分)。
例如:
"hosting":
"rewrites": [
"source":"**",
"destination": "/index.html"
]
希望这可以为其他人节省大量的挫败感和浪费的时间。
编码愉快...
进一步阅读该主题:
https://firebase.google.com/docs/hosting/full-config#rewrites
Firebase CLI: "Configure as a single-page app (rewrite all urls to /index.html)"
【讨论】:
你是个传奇 非常感谢。很棒的解决方案!【参考方案27】:我喜欢这种处理方式。尝试添加: yourSPAPageRoute/* 在服务器端摆脱这个问题。
我采用了这种方法,因为即使是原生 HTML5 History API 也不支持页面刷新时的正确重定向(据我所知)。
注意:选定的答案已经解决了这个问题,但我正在尝试更具体。
Express Route
经过测试,只是想分享一下。
希望对你有帮助。
【讨论】:
【参考方案28】:修复刷新或直接调用 URL 时出现的“无法获取 /URL”错误。
配置您的 webpack.config.js 以期望给定的链接是这样的路由。
module.exports =
entry: './app/index.js',
output:
path: path.join(__dirname, '/bundle'),
filename: 'index_bundle.js',
publicPath: '/'
,
【讨论】:
【参考方案29】:我为我的 SPA 找到了带有反应路由器 (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>
来源:https://gist.github.com/alexsasharegan/173878f9d67055bfef63449fa7136042
【讨论】:
【参考方案30】:带有示例的完整路由器(React Router v4):
示例工作示例查看下面的项目。
react-router-4-example
下载后 1.) cmd中的“npm install”安装项目 2.) "npm start" 启动你的 react 应用
注意:您需要 Node js 软件才能在您的 Windows 中运行。 Mac OS 有节点默认值。
干杯
【讨论】:
以上是关于手动刷新或写入时,React-router url 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
刷新浏览器时如何使react-router v4:id-path工作?
react-router browserHistory刷新页面404问题解决方法