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

Posted

技术标签:

【中文标题】手动刷新或写入时,React-router url 不起作用【英文标题】:React-router urls don't work when refreshing or writing manually 【发布时间】:2015-03-11 18:38:25 【问题描述】:

我正在使用 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】:

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

文件在项目中的位置:

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>

【讨论】:

【参考方案2】:

您可以将 Vercel 的托管用于您的 react 应用程序,并使用 BrowserRouting 在您的 react 应用程序中使用相同的旧路由方式。

您需要在项目的根目录下添加一个 vercel.json 文件,并将此代码添加到其中:


  "rewrites": [
    
      "source": "/((?!api/.*).*)",
      "destination": "/index.html"
    
  ]

这非常好,希望对您有所帮助。

【讨论】:

【参考方案3】:

HashRouter 将是一个简单的实现,

import HashRouter as Router,Switch,Route,Link from 'react-router-dom';


  function App() 
  return (
    <Router>
        <Switch>
          <Route path="/" exact component=InitialComponent />
          <Route path="/some" exact component=SomeOtherComponent />
        </Switch>
      </Router>
  );

在浏览器中会是这样的—— http:localhost:3000/#/ , http:localhost:3000/#/some

【讨论】:

【参考方案4】:

当我将 React 用于前端并使用 react-router-dom 进行路由时,我在 Electron 中遇到了这个问题。 我用HashRouter 替换了BrowserRouter,它已修复。 这是一个简单的例子

import 
  HashRouter as Router,
  Switch,
  Route,
 from "react-router-dom";

【讨论】:

这是一个救命稻草,经过几天的研究,只需将BrowerRouter 更改为HashRouter,就解决了我几天来面临的链接或&lt;a href=" &gt;&lt;/a&gt; 问题。我希望有一天这对遇到同样问题的其他人有用,您只需import HashRouter as Router, Switch, Route from "react-router-dom"【参考方案5】:

已经非常棒的答案了!!但是,如果您使用 nginx 进行托管并且需要快速修复... 将以下行添加到位置块内的 nginx 配置中

location / 
  try_files $uri /index.html;

【讨论】:

【参考方案6】:

在我的情况下,当我在其中使用参数时,url 没有加载。

作为快速修复,我添加 &lt;base href="&lt;yourdomain/IP&gt;"&gt;&lt;/base&gt; 在 build 文件夹中 index.html 文件的标签下。

这正好解决了我的问题。

【讨论】:

【参考方案7】:

查看已接受答案的 cmets 和此问题的一般性质(“不工作”),我认为这可能是对此处涉及的问题进行一些一般性解释的好地方。因此,此答案旨在作为 OP 特定用例的背景信息/详细说明。请多多包涵。

服务器端与客户端

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

使用 React-Router 提供的客户端路由,事情就不那么简单了。起初,客户端还没有加载任何 JS 代码。所以第一个请求将永远是服务器。然后将返回一个页面,其中包含加载 React 和 React Router 等所需的脚本标签。只有当这些脚本加载后,第二阶段才会开始。例如,在第 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 改变了他们的实现。他们现在有不同的路由器实例用于不同的历史记录,并且他们在后台配置历史记录。基本原理还是一样的。【参考方案8】:

如果你使用“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/**),任何到达该端点的请求都将重定向到响应应用程序(index.html 文件),react-router 会处理这些后记。

【讨论】:

你也可以像这样添加多个映射:@RequestMapping("/myurl1/**", "/myurl2/**")【参考方案9】:

我知道这个问题已经被回答到死了,但是它并没有解决你想使用代理通道的浏览器路由器的问题,你不能使用 root。

对我来说,解决方案非常简单。

假设你有一个指向某个端口的 url。

location / 
  proxy_pass http://127.0.0.1:30002/;
  proxy_set_header    Host            $host;
  port_in_redirect    off;

现在由于浏览器路由器的子路径已损坏。但是你知道子路径是什么。

解决方案?对于子路径/contact

# just copy paste.
location /contact/ 
  proxy_pass http://127.0.0.1:30002/;
  proxy_set_header    Host            $host;

我尝试过的其他方法都无效,但这个简单的修复方法就像一个该死的魅力。

【讨论】:

【参考方案10】:

这可以解决你的问题

我在生产模式下的 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"?,我正在使用&lt;BrowserRouter&gt; .htaccess 为我修复了它。 在哪里,我将在解决方案 2 中获取 browserHistory。 在为我修复的构建文件夹中仅添加 .htaccess 文件,谢谢伙计 为什么会有人sudo build【参考方案11】:

在后端使用 express 并在前端使用 React(没有 react-create-app)和reach/router,正确的reach/router route react 组件会显示出来,并且在点击进入时菜单链接设置为活动样式地址栏,例如 http://localhost:8050/pages。请在下面结帐,或直接到我的仓库https://github.com/nickjohngray/staticbackeditor,所有代码都在那里。

Webpack

设置代理。这允许来自端口 3000(React)的任何调用调用服务器 包括在按下回车键时调用 get index.html 或地址栏中的任何内容。它还允许调用 API 路由,以获取 JSON 数据

like await axios.post('/api/login', email, pwd)

devServer: 
    port: 3000,
    open: true,
    proxy: 
      '/': 'http://localhost:8050',
    
  

设置快速路线

app.get('*', (req, res) => 
    console.log('sending index.html')
    res.sendFile(path.resolve('dist', 'index.html'))

);

这将匹配来自 react 的任何请求, 它只返回 index.html 页面,该页面位于我的 dist 文件夹中 当然,这个页面有一个更多的单页反应应用程序。 (注意任何其他路由都应该出现在上面,在我的例子中,这些是我的 API 路由)

反应路线

<Router>
    <Home path="/" />
    <Pages path="pages"/>
    <ErrorPage path="error"/>
    <Products path="products"/>
    <NotFound default />
</Router>

这些路由是在我的 Layout 组件中定义的,当路径匹配时会加载相应的组件。

React 布局构造函数

 constructor(props) 
        super(props);


        this.props.changeURL(URL: globalHistory.location.pathname);

Layout 构造函数在加载后立即被调用。在这里,我调用我的菜单监听的 redux 操作 changeURL,以便它可以突出显示正确的菜单项,如下所示:

菜单代码

<nav>
    this.state.links.map( (link) =>
    <Link className=this.getActiveLinkClassName(link.path)  to=link.path> 
      link.name
    </Link>)            
</nav>

【讨论】:

【参考方案12】:

对于那些因为试图从 IIS 虚拟目录(而不是网站的根目录)提供 react 应用程序而来到这里的人,那么这可能适合你。

在设置重定向时,'/' 不能单独工作,对我来说,它也需要其中的虚拟目录名称。这是我的网络配置的样子:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <defaultDocument>
            <files>
                <remove value="default.aspx" />
                <remove value="iisstart.htm" />
                <remove value="index.htm" />
                <remove value="Default.asp" />
                <remove value="Default.htm" />
            </files>
        </defaultDocument>
        <rewrite>
            <rules>
                <rule name="React Routes" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="REQUEST_FILENAME" matchType="IsFile" negate="true" />
                        <add input="REQUEST_FILENAME" matchType="IsDirectory" negate="true" />
                        <add input="REQUEST_URI" pattern="^/(api)" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/YOURVIRTUALDIRECTORYNAME/" />
                </rule>
            </rules>
        </rewrite>
        <directoryBrowse enabled="false" />
        <httpErrors errorMode="Custom" defaultResponseMode="ExecuteURL">
            <remove statusCode="500" subStatusCode="100" />
            <remove statusCode="500" subStatusCode="-1" />
            <remove statusCode="404" subStatusCode="-1" />
            <remove statusCode="403" subStatusCode="18" />
            <error statusCode="403" subStatusCode="18" path="/YOURVIRTUALDIRECTORYNAME/" responseMode="ExecuteURL" />
            <error statusCode="404" path="/YOURVIRTUALDIRECTORYNAME/" responseMode="ExecuteURL" />
            <error statusCode="500" prefixLanguageFilePath="" path="/YOURVIRTUALDIRECTORYNAME/" responseMode="ExecuteURL" />
            <error statusCode="500" subStatusCode="100" path="/YOURVIRTUALDIRECTORYNAME/" responseMode="ExecuteURL" />
        </httpErrors>
    </system.webServer>
</configuration>

除了 web.config 文件之外,react 应用程序本身还需要一些更改:

您需要在 package.json 中添加一个“主页”条目:


  "name": "sicon.react.crm",
  "version": "0.1.0",
  "private": true,
  "homepage": "/YOURVIRTUALDIRECTORYNAME/",
  "dependencies": 
...

我将基本名称添加到我的浏览器历史记录对象中,我将其传递给路由器以访问历史记录:

import  createBrowserHistory  from 'history';

export default createBrowserHistory(
    //Pass the public URL as the base name for the router basename: process.env.PUBLIC_URL
);

我还在 App.js 中的 React 路由器上添加了这个属性:

  <Router history=history basename=process.env.PUBLIC_URL>

最后,在 index.html 中,我在“标题”标签上方添加了以下标签

  <base href="%PUBLIC_URL%/">

可能是一些需要注意的步骤,但这似乎已经为我完成了这项工作。我不知道如何将其设置为在站点的根目录或虚拟目录中运行而无需重新编译,尽管据我所知,package.json 中的主页在构建后无法交换.

【讨论】:

您帖子中的最后两行代码救了我。谢谢! basename 在 index.html 中的 &lt;Router /&gt;&lt;base /&gt; @CraigHowell - 很高兴它有帮助!我也回到这个帖子来提醒自己!【参考方案13】:

我正在使用 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",
  ...

【讨论】:

【参考方案14】:

如果您在 Google 存储桶上运行它,解决此问题的简单方法是为错误(404 未找到)页面考虑“index.html”。

这样做:

    在存储桶列表中,找到您创建的存储桶。 单击与存储桶关联的存储桶溢出菜单 (...),然后选择编辑网站配置。 在网站配置对话框中,也将主页指定为错误页面。

【讨论】:

【参考方案15】:

即使您立即指向 url,请求数据的另一种方法是让每个组件都有一个方法来调用最后一个参数,例如 /about/test,然后再调用您的 State Provider具有连接到您要请求数据的组件的功能

【讨论】:

【参考方案16】:

我使用的是 .Net Core 3.1,刚刚添加了扩展 MapFallbackToController

Startup.cs

    app.UseEndpoints(endpoints =>
    
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "controller=Home/action=Index/id?");

        endpoints.MapFallbackToController("Index", "Home");
    );

【讨论】:

【参考方案17】:

我通过更改 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

【讨论】:

【参考方案18】:

将此添加到webpack.config.js

devServer: 
    historyApiFallback: true

【讨论】:

这对开发人员来说很棒,但对生产构建没有帮助。 谢谢你... 真的把它修好了 为我工作! ?【参考方案19】:

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

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();

【讨论】:

【参考方案20】:

对于 React Router V4 用户:

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

<Router history=hashHistory >

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

import  HashRouter  from 'react-router-dom'

<HashRouter>
  <App/>
</HashRouter>

参考:HashRouter

【讨论】:

您能否详细说明 HashRouter 解决此问题的原因?您提供的链接没有为我解释。另外,有没有办法隐藏路径中的哈希?我使用的是 BrowserRouter,但遇到了这个 404 问题.. 我正在使用浏览器路由器,刷新时导致 404 错误,但后来我用哈希路由器替换了浏览器路由器,但它不能正常工作。谢谢【参考方案21】:

您可以更改您的 .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 之后的路径与应用程序所在的文件夹匹配(如果它是子文件夹)【参考方案22】:

虽然不是我的,但你可以尝试阅读所有内容:

https://www.andreasreiterer.at/fix-browserrouter-on-apache/

修复应用的路由 现在这是最终修复路由的方法。要告诉 Apache 将请求重定向到我们的应用程序所在的 index.html,我们必须修改 .htaccess 文件。如果您的应用文件夹中还没有此类文件,请创建它。

然后确保你输入了那 4 行,它们会神奇地让你的路由工作。

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

在我们将该 .htaccess 文件放入与 index.html 相同的目录后,Apache 会将每个新请求直接重定向到您的应用程序。

奖励:将 React 应用程序部署到子目录

如果您将应用部署到子目录中,那么它可以访问,例如通过https://myapp.com/the-app,您很快就会注意到还有另一个问题。每次点击新路由都会将 URL 转换为 https://myapp.com/route-abc 之类的东西——重新加载后会再次中断。但是有一个简单的解决方法:

BrowserRouter 有一个名为 basename 的属性,您可以在其中指定子目录路径:

从现在开始,每个像 /contacts 这样的路由都会产生像 http://myapp.com/the-app/contacts 这样的 URL。

【讨论】:

对于那些想从不同目录运行 CRA 的人来说,这是一个非常简单的解决方法。我正在使用react-router-dom,所以我必须在&lt;BrowserRouter /&gt; 中包含basename。但是这个简单的修复将为您节省大量时间。感谢您的贡献! 谢谢。您的解决方案节省了我的时间。 :) 很高兴我能帮上忙.. :)【参考方案23】:

我们使用express' 404 handling approach

// path to the static react build directory    
const frontend = path.join(__dirname, 'react-app/build');

// map the requests to the static react build directory
app.use('/', express.static(frontend));

// all the unknown requests are redirected to the react SPA
app.use(function (req, res, next) 
    res.sendFile(path.join(frontend, 'index.html'));
);

像魅力一样工作。现场演示是our site

【讨论】:

这对我有用,谢谢你的回答!【参考方案24】:

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

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

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

【讨论】:

【参考方案25】:

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

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

【讨论】:

这是最简单的解决方案。请注意,这条路线应该任何其他路线之后去,因为它是一个全部 从“”更改为“/”为我解决了类似的问题。但是,浏览器在刷新或 URL 导航时收到了一个空的 HTML,而不是作为 OP 收到错误“无法 GET”。【参考方案26】:

如果您在 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>

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

【讨论】:

【参考方案27】:

这里的答案都非常有帮助,对我有用的是配置我的 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。谢谢【参考方案28】:

这是我发现的一个前端解决方法,它不需要修改服务器上的任何内容。

假设您的网站是 mysite.com,并且您有一条到 mysite.com/about 的 React 路由。 在 index.js 中,你挂载你的***组件,你可以像这样放置另一个路由器:

ReactDOM.render(
<Router>
    <div>
        <Route exact path="/" component=Home />
        <Route exact path="/about"
            render=(props) => <Home ...props refreshRout="/about"/>
        />
    </div>
</Router>,

我假设您的原始路由器位于虚拟 DOM 中***组件下方的某个位置。如果您使用 Django,您还必须在 .urls 中捕获 url:

urlpatterns = [
       path('about/', views.index),
]

不过,这取决于您使用的后端。请求 mysite/about 将使您进入 index.js(您安装***组件的位置),您可以在其中使用 Route 的 render 道具,而不是 component 道具,并将 '/about' 作为道具传递给,这个例子是 Home 组件。

在 Home 中,在 componentDidMount() 或 useEffect() 挂钩中,执行以下操作:

useEffect()    
   //check that this.props.refreshRoute actually exists before executing the 
   //following line    
   this.props.history.replace(this.props.refreshRoute);

我假设您的 Home 组件正在呈现如下内容:

<Router>
   <Route exact path="/" component=SomeComponent />
   <Route path="/about" component=AboutComponent />
</Router>

感谢 (Pass props to a component rendered by React Router) 如何将 props 传递给 Routes 中的组件。

【讨论】:

【参考方案29】:

使用 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

【讨论】:

【参考方案30】:

我正在使用 WebPack,我遇到了同样的问题解决方案=> 在你的 server.js 文件中

const express = require('express');
const app = express();

app.use(express.static(path.resolve(__dirname, '../dist')));
  app.get('*', function (req, res) 
    res.sendFile(path.resolve(__dirname, '../dist/index.html'));
    // res.end();
  );

Why doesn't my application render after refreshing?

【讨论】:

这是为我做的!最初我有 res.sendFile(path.JOIN(publicPath, "index.html"));我将“join”更改为“resolved”,就像上面的示例一样: res.sendFile(path.resolve("./dist", "index.html"));我也在玩 __dirname 但不能真正理解它或让它工作,所以我手动复制到“./dist”中,因为这是我的 index.html 的来源。我之前也这样声明过:app.use(express.static("./dist"));

以上是关于手动刷新或写入时,React-router url 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

刷新浏览器时如何使react-router v4:id-path工作?

react-router 如何在页面刷新时保持位置状态?

react-router browserHistory刷新页面404问题解决方法

React-router typed-url 并在 tomcat、弹性 beanstalk 上刷新

react-router 同一路由,参数不同,页面没有刷新

在 react-router 中路由嵌套 url