我正在使用React-router,当我点击链接按钮时,它工作得很好,但当我刷新我的网页时,它没有加载我想要的东西。

例如,我在localhost/joblist和一切都很好,因为我到达这里按下一个链接。但如果我刷新网页,我会得到:

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

当前回答

将此添加到webpack.config.js:

devServer: {
    historyApiFallback: true
}

其他回答

你可以在你的React应用程序中使用Vercel的主机,并使用相同的旧方式在你的React应用程序中使用BrowserRouting。

您需要添加一个vercel。Json文件在你的项目的根,并添加以下代码:

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

这工作得非常好。

服务器端与客户端

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

With client-side routing, which is what React Router provides, things are less simple. At first, the client does not have any JavaScript code loaded yet. So the very first request will always be to the server. That will then return a page that contains the needed script tags to load React and React Router, etc. Only when those scripts have loaded does phase 2 start. In phase 2, when the user clicks on the 'About us' navigation link, for example, the URL is changed locally only to http://example.com/about (made possible by the History API), but no request to the server is made. Instead, React Router does its thing on the client-side, determines which React view to render, and renders it. Assuming your about page does not need to make any REST calls, it's done already. You have transitioned from Home to About Us without any server request having fired.

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

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

你的麻烦就从这里开始了。到目前为止,您只需要在服务器的webroot中放置一个静态HTML就可以了。但是,当从服务器请求其他url时,会出现404错误。这些相同的url在客户端工作得很好,因为有React路由器为你做路由,但它们在服务器端失败,除非你让你的服务器理解它们。

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

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

这就是你的选择开始的地方。解决方案包括完全绕过这个问题(通过一个返回引导HTML的全面路径),以及完全同构的方法(服务器和客户端都运行相同的JavaScript代码)。

完全绕过这个问题:哈希历史

使用哈希历史,而不是浏览器历史,你的关于页面的URL看起来像这样: http://example.com/#/about

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

缺点:

“丑陋”的url 使用这种方法不可能实现服务器端呈现。就搜索引擎优化(SEO)而言,你的网站由一个单一的页面组成,上面几乎没有任何内容。

全方位

使用这种方法,您确实使用了浏览器历史记录,但只是在服务器上设置了一个将/*发送到index.html的“捕捉器”,有效地为您提供了与使用散列历史记录相同的情况。不过,你确实有干净的url,你可以在以后改进这个方案,而不必使所有用户的收藏夹无效。

缺点:

设置起来更加复杂 仍然没有好的SEO

混合动力

在混合方法中,通过为特定的路由添加特定的脚本,您可以扩展“全方位”场景。你可以编写一些简单的PHP脚本,返回包含内容的网站最重要的页面,这样Googlebot至少可以看到你的页面上有什么。

缺点:

设置起来更加复杂 只有好的SEO,你给那些路线的特殊待遇 复制在服务器和客户端上呈现内容的代码

同构

如果我们使用Node.js作为服务器,那么我们可以在两端运行相同的JavaScript代码呢?现在,我们已经在一个react-router配置中定义了所有的路由,我们不需要复制呈现代码。可以说,这是“圣杯”。如果页面转换发生在客户端上,服务器发送的标记与我们最终得到的标记完全相同。这个解决方案在SEO方面是最优的。

缺点:

服务器必须(能够)运行JavaScript。我曾尝试将Java与Nashorn结合使用,但它并不适合我。实际上,这主要意味着你必须使用基于Node.js的服务器。 许多棘手的环境问题(在服务器端使用窗口等) 陡峭的学习曲线

我应该用哪一种?

选择一个你可以逃避惩罚的。就我个人而言,我认为这是一个非常简单的设置,所以这将是我的最小值。这种设置可以让你随着时间的推移不断改进。如果你已经使用Node.js作为你的服务器平台,我肯定会研究做一个同构应用程序。是的,一开始很难,但一旦你掌握了它,它实际上是一个非常优雅的解决问题的方法。

所以基本上,对我来说,这就是决定因素。如果我的服务器运行在Node.js上,我会采用同构;否则,我会去抓所有的解决方案,只是扩展它(混合解决方案)随着时间的推移和搜索引擎优化的需求。

如果你想了解更多关于React的同构(也称为“通用”)渲染,这里有一些关于这个主题的很好的教程:

用同构应用应对未来 在ReactJS中创建同构应用的痛苦和快乐 如何实现Node + React同构JavaScript &为什么它很重要

另外,为了让你开始学习,我建议你看看一些入门套件。选择一个与你的技术堆栈选择相匹配的(记住,React只是MVC中的V,你需要更多的东西来构建一个完整的应用程序)。先来看看Facebook自己发布的一篇文章:

创建React应用

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

选择你最完美的React启动项目

我从这些开始:

React同构启动器 React Redux通用热示例

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

祝你好运!

如果你正在使用Firebase,你所要做的就是确保你的Firebase中有一个重写属性。Json文件在你的应用程序的根(在托管部分)。

例如:

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

有关此主题的进一步阅读:

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

我使用React.js + Webpack模式。我在package中添加了——history-api-fallback参数。json文件。此时页面刷新工作正常。

每次我修改代码时,网页都会自动刷新。

"scripts": {
  "start": "rimraf build && cross-env NODE_ENV='development' webpack --mode development && cross-env NODE_ENV=development webpack-dev-server --history-api-fallback",
  ...
}

如果你正在使用Apache并且没有。htaccess文件,这是一个适合我的配置文件:

sites-enabled/somedomain.com.conf

<VirtualHost *:80>
    ServerName somedomain.com
    ServerAlias *.somedomain.com
    DocumentRoot /www/somedomain.com/build

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /www/somedomain.com/build/index.html [L,NC,QSA]

</VirtualHost>