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

时间:2015-01-13 17:51:54

标签: javascript url reactjs router react-router

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

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

Cannot GET /joblist

默认情况下,它没有像这样工作。最初我将我的网址设为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);
});

50 个答案:

答案 0 :(得分:789)

看看对已接受答案的评论以及这个问题的一般性质(不工作&#39;),我认为这可能是一个关于一些一般性解释的好地方这里涉及的问题。因此,这个答案旨在作为OP的具体用例的背景信息/详细说明。请耐心等待。

服务器端与客户端

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

使用React-Router提供的客户端路由,事情就不那么简单了。起初,客户端尚未加载任何JS代码。所以第一个请求将永远是服务器。然后,它将返回一个页面,其中包含所需的脚本标记以加载React和React Router等。只有当这些脚本加载时才会启动第2阶段。在第2阶段,当用户点击“关于我们”时,例如,导航链接,URL仅在本地更改为http://example.com/about(由History API生成),但未向服务器发出请求。相反,React Router在客户端执行其操作,确定要呈现和呈现的React视图。假设您的about页面不需要进行任何REST调用,那么它已经完成了。您已经从Home转换为About Us而没有任何服务器请求被解雇。

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

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

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

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

如果您希望http://example.com/about URL在服务器端和客户端都可以工作,则需要在服务器端和客户端为它设置路由。有道理吗?

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

完全绕过问题:哈希历史

使用Hash History代替Browser History,about页面的网址如下所示: http://example.com/#/about 散列(#)符号后面的部分不会发送到服务器。因此服务器只看到http://example.com/并按预期发送索引页。 React-Router将选择#/about部分并显示正确的页面。

下行

  • &#39;难看&#39;网址
  • 使用此方法无法进行服务器端呈现。就搜索引擎优化(SEO)而言,您的网站包含一个页面,几乎没有任何内容。

捕捉-所有

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

下行

  • 设置更复杂
  • 仍然没有好的SEO

混合

在混合方法中,您可以通过为特定路由添加特定脚本来扩展catch-all场景。您可以制作一些简单的PHP脚本来返回包含内容的网站中最重要的页面,因此Googlebot至少可以查看您网页上的内容。

<强>缺点

  • 设置更复杂
  • 对于那些给予特殊待遇的路线,只有优秀的搜索引擎优化
  • 复制用于在服务器和客户端上呈现内容的代码

同构

如果我们使用Node JS作为我们的服务器,那么我们可以在两端运行相同的 JS代码怎么办?现在,我们在单个react-router配置中定义了所有路由,并且我们不需要复制渲染代码。这是圣杯&#39;可以这么说。如果在客户端上发生页面转换,服务器将发送完全相同的标记。这个解决方案在SEO方面是最佳的。

<强>缺点

  • 服务器必须(能够)运行JS。我已经尝试过Java i.c.w. Nashorn但它并不适合我。在实践中,它主要意味着您必须使用基于Node JS的服务器。
  • 许多棘手的环境问题(在服务器端使用window等)
  • 陡峭的学习曲线

我应该使用哪种颜色?

选择您可以逃脱的那个。就我个人而言,我觉得这一切都足够简单,所以这将是我的最低限度。此设置允许您随着时间的推移改进。如果您已经使用Node JS作为服务器平台,我肯定会调查做同构应用程序。是的,一开始很难,但是一旦掌握了它,它实际上是解决问题的一个非常优雅的解决方案。

所以基本上,对我来说,这将是决定因素。如果我的服务器在Node JS上运行,我会变得同构;否则我会选择Catch-all解决方案并随着时间的推移扩展它(混合解决方案)并且SEO要求它。

如果您想了解更多有关使用React进行同构(也称为“通用&#39;”渲染)的更多信息,可以参考以下主题:

另外,为了帮助您入门,我建议您查看一些入门套件。选择一个符合您对技术堆栈的选择(请记住,React只是MVC中的V,您需要更多东西来构建完整的应用程序)。首先看看Facebook本身发布的那个:

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

我从这些开始:

目前我使用的是通用渲染的家庭酿造版本,其灵感来自上面的两个入门套件,但它们现在已经过时了。

祝你好运!

答案 1 :(得分:91)

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

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

historyApiFallback是解决这个问题的原因。现在路由工作正常,我可以刷新页面或直接输入URL。无需担心节点服务器上的解决方法。这个答案显然只有在您使用webpack时才有效。

编辑:请在此处查看我的答案,了解为何需要这样做的更详细原因: https://stackoverflow.com/a/37622953/5217568

答案 2 :(得分:43)

React Router V4 用户:

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

<Router history={hashHistory} >

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

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

<HashRouter>
  <App/>
</HashRouter>

参考: https://reacttraining.com/react-router/web/api/HashRouter

答案 3 :(得分:41)

您可以更改htaccess并插入:

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

我正在使用react: "^15.3.2"react-router: "^3.0.0"history: "^4.3.0"

答案 4 :(得分:27)

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

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

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

例如,在快递中,它可能如下所示:

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。

答案 5 :(得分:19)

在index.html head中,添加以下内容:

<base href="/">
<!-- This must come before the css and javascripts -->

然后在使用webpack dev server运行时使用此命令。

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

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

答案 6 :(得分:14)

Webpack Dev Server可以选择启用此功能。打开package.json并添加--history-api-fallback。 这个解决方案对我有用。

https://github.com/reactjs/react-router-tutorial/tree/master/lessons/10-clean-urls#configuring-your-server

答案 7 :(得分:13)

我刚刚使用create-react-app创建了一个网站,并在此处提出了相同的问题。我使用BrowserRouting包中的react-router-dom。我在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

答案 8 :(得分:12)

如果您通过AWS Static S3 Hosting&amp ;;托管反应应用程序CloudFront的

此问题由CloudFront以403 Access Denied消息响应,因为它预期/某些/其他/路径存在于我的S3文件夹中,但该路径仅存在于React与react-router的路由中。

解决方案是设置分发错误页面规则。转到CloudFront设置并选择您的分发。接下来转到“错误页面”选项卡。单击“创建自定义错误响应”并为403添加条目,因为这是我们获得的错误状态代码。将响应页面路径设置为/index.html,将状态代码设置为200.最终结果令我惊讶于它的简单性。提供了索引页面,但URL保留在浏览器中,因此一旦反应应用程序加载,它将检测URL路径并导航到所需的路径。

Error Pages 403 Rule

答案 9 :(得分:12)

这可以解决您的问题

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

1.将路由历史记录更改为“hashHistory”而不是browserHistory代替

customClass="MyOldControllerName"

现在使用命令

构建应用程序
customClass="MyNewControllerName"

然后将构建文件夹放在var / www /文件夹中,现在应用程序正常工作,并在每个URL中添加#tag。喜欢

本地主机/#/家    本地主机/#/公司简介

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

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

您需要创建“conf”文件来解决404未找到的页面, conf文件应该是这样的。

打开你的终端输入以下命令

cd / etc / apache2 / sites-available LS nano sample.conf 在其中添加以下内容。

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

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

sudo npm run build

然后它会要求你重新加载apache服务器,使用      sudo service apache2 reload or restart

然后打开localhost / build文件夹并添加.htaccess文件,其中包含以下内容。

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

现在应用程序正常运行。

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

如果对此有任何疑问,请随时提出评论。

我希望它对其他人有所帮助。

答案 10 :(得分:8)

生产堆栈:React,React Router v4,BrowswerRouter,Express,Nginx

1)针对漂亮网址的用户浏览器

// 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.jsnode server.js

编辑:你可能想让nginx在服务器块中处理这个并忽略第2步:

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

答案 11 :(得分:8)

将此添加到webpack.congif.js

devServer: {
      historyApiFallback: true
  }

答案 12 :(得分:6)

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

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

RewriteRule ^ /index.html [L]  

答案 13 :(得分:5)

如果您使用的是Create React App:

对于许多主要托管平台的解决方案,您可以在Create React App页面上找到HERE,这是一个很好的解决方案。例如,我使用React Router v4和Netlify作为我的前端代码。所需要的只是将1个文件添加到我的公共文件夹(&#34; _redirects&#34;)和该文件中的一行代码:

/*  /index.html  200

现在,我的网站在进入浏览器或有人点击刷新时正确呈现了像mysite.com/pricing这样的路径。

答案 14 :(得分:3)

这个主题有点陈旧并且已经解决,但我想建议一个简单,清晰和更好的解决方案。如果您使用Web服务器,它可以工作。

每个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

就是这样,没有更多魔法需要:)

答案 15 :(得分:3)

如果您在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错误,并且不需要使用哈希历史记录。

答案 16 :(得分:2)

我找到了带有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>

来源:https://gist.github.com/alexsasharegan/173878f9d67055bfef63449fa7136042

答案 17 :(得分:2)

使用$v1 = null; echo (isset($v1) ? '$v1 set' : '$v1 not set') . PHP_EOL; echo (is_null($v1) ? '$v1 null' : '$v1 not null') . PHP_EOL; echo (empty($v1) ? '$v1 empty' : '$v1 not empty') . PHP_EOL; echo (array_key_exists('v1', get_defined_vars()) ? '$v1 defined' : '$v1 not defined') . PHP_EOL; echo PHP_EOL; echo (isset($v2) ? '$v2 set' : '$v2 not set') . PHP_EOL; echo (@is_null($v2) ? '$v2 null' : '$v2 not null') . PHP_EOL; echo (empty($v2) ? '$v2 empty' : '$v2 not empty') . PHP_EOL; echo (array_key_exists('v2', get_defined_vars()) ? '$v2 defined' : '$v2 not defined') . PHP_EOL; Redux 也很有效,只需替换:

$v1 not set
$v1 null
$v1 empty
$v1 defined

$v2 not set
$v2 null
$v2 empty
$v2 not defined

收件人:

array_key_exists(..., get_defined_vars())

答案 18 :(得分:2)

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

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

答案 19 :(得分:2)

如果您使用的是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)"

答案 20 :(得分:2)

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

我的主要jsx包含:

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

这适用于第一个匹配的链接但是当{id}更改嵌套在该模型的详细信息页面上的<Link>表达式时,网址中的网址会发生变化,但页面的内容却没有最初改变以反映链接的模型。

问题在于我使用props.params.idcomponentDidMount中设置模型。组件刚刚安装一次,这意味着第一个模型是粘在页面上的模型,随后的链接会更改道具,但让页面保持不变。

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

答案 21 :(得分:2)

如果确实有index.html的后备,请确保在index.html文件中有这个:

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

这可能因项目而异。

答案 22 :(得分:1)

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

.profile-img-container img:hover {
    opacity: 0.5
}

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

答案 23 :(得分:1)

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

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

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

最重要的部分是“ --history-api-fallback”,用于启用历史记录API回调。

如果您使用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会处理这些后遗症。

答案 24 :(得分:1)

当我使用.Net Core MVC时,这样的东西对我有所帮助:

    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var url = Request.Path + Request.QueryString;
            return App(url);
        }

        [Route("App")]
        public IActionResult App(string url)
        {
            return View("/wwwroot/app/build/index.html");
        }
   }

基本上在MVC端,所有不匹配的路由都将归入Home/Index中指定的startup.cs中。在Index内部,可以获取原始请求url并将其传递到任何需要的地方。

  

startup.cs

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });

答案 25 :(得分:1)

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

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

这刚好解决了我的问题。

答案 26 :(得分:1)

如果有人在这里寻找使用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'时,它首先在服务器端加载。由于在服务器端,此位置没有任何内容,因此返回未找到。如果你有这个可选的路由器,它会加载同一个页面并且反应路由器也被加载,然后反应加载器决定显示哪个组件。 希望这会有所帮助。

答案 27 :(得分:1)

如果你在后端使用Express或其他框架,你可以添加如下的类似配置并查看配置中的Webpack公共路径,如果你使用的是BrowserRouter,它应该可以很好地重新加载

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

答案 28 :(得分:0)

我知道这个问题已经死了,但它并不能解决您要通过代理传递使用浏览器路由器而不能使用root的问题。

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

假设您的网址指向某个端口。

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

我没有尝试过其他任何方法,但是这个简单的修复方法就像该死的魅力。

答案 29 :(得分:0)

我正在使用React.js + Webpack模式。我在--history-api-fallback文件中添加了package.json参数。然后页面刷新工作正常。 每次更改代码时,网页都会自动刷新。

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

答案 30 :(得分:0)

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

答案 31 :(得分:0)

在具有到达/路由器的后端上使用Express并在前端使用React(不带react-create-app),将显示正确的到达/路由器路由react组件,并在按Enter键时将菜单链接设置为活动样式地址栏,例如http:// localhost:8050 / pages。请在下面结帐,或直接转到我的仓库https://github.com/nickjohngray/staticbackeditor,所有代码都在这里。

Webpack

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

就像等待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文件夹中 当然,此页面还有一个单页面的React应用。 (请注意,其他路线也应显示在此上方,在我的情况下,这是我的API路线)

反应路线

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

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

反应式布局构造函数

 constructor(props) {
        super(props);


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

布局构造函数在加载后立即被调用。在这里,我将我的菜单侦听的redux action changeURL称为菜单URL,以便它可以突出显示正确的菜单项,如下所示:

菜单代码

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

答案 32 :(得分:0)

对于那些因为试图从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中的主页在生成后无法交换到我为止。我知道。

答案 33 :(得分:0)

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

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

答案 34 :(得分:0)

如果您在Google Bucket上运行它,简单的解决方案是考虑使用“ index.html”查找错误(找不到404页)。

要这样做:

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

答案 35 :(得分:0)

即使您立即直接指向url,请求数据的另一种方法是使每个组件都具有一种方法,该方法调用最后一个参数,例如/ about / test ,然后调用您的State Provider。具有使用

连接到您要请求数据的组件的功能

答案 36 :(得分:0)

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

答案 37 :(得分:0)

您可以尝试阅读所有内容,尽管这不是我的:

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

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

然后确保您输入的这4行将神奇地使您的路由工作。

s = cumsum(VItimeseries,1);     % cumulative sum explicitly along columns
s2 = cumsum(VItimeseries.^2,1);
n = (1:size(VItimeseries,1)).'; % use number of rows, rather than `numel`.
v = (s2 - s.^2 ./ n) ./ (n-1);
v(1,:) = 0;                     % fill first row with zeros, not just first element

将.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。

答案 38 :(得分:0)

我们使用了express' 404 handling approach

import math
def readFileIntoAList(file,N):
    lines= list()
    lines1 = list()
    with open(file) as f:
        lines1 = [lineNew.rstrip("\n") for lineNew in f]
        for a in range(math.ceil(len(lines1)/N)):
            lines.append((*lines1[a*N:(a+1)*N],))
    return lines

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

答案 39 :(得分:0)

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

假设您的网站是mysite.com,并且您有一个通往mysite.com/about的React Route。 在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的渲染道具(而不是组件道具),并在其中传递“ / 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>

https://tylermcginnis.com/react-router-pass-props-to-components/致谢,以了解如何将道具传递到路线中的组件。

答案 40 :(得分:0)

如果您来这里是在使用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>

答案 41 :(得分:0)

假设您具有以下本地路由定义

<Route exact path="/" render={routeProps => (
   <Home routeProps={routeProps}/>
)}/>

{/*optional catch-all router */}
<Route render={routeProps => (
       <div><h4>404 not found</h4></div>
)}/>

在您的Home组件上,您可以在ComponentWillMount事件中拦截请求,

const searchPath = this.props.routeProps.location.search;

if (searchPath){
    this.props.routeProps.history.push("/" + searchPath.replace("?",""));
}
else{
    /*.... originally Home event */
}

现在,您可以请求/?joblist,而不是在url上调用/ joblist,组件将自动将请求重定向到/ joblist(请注意路径中的额外问号)

答案 42 :(得分:0)

我正在使用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();
  });

https://github.com/ReactTraining/react-router/blob/master/FAQ.md#why-doesnt-my-application-render-after-refreshing

答案 43 :(得分:0)

带有示例的完整路由器(React Router v4):

示例工作示例检出以下项目。

https://github.com/eh3rrera/react-router-4-example

下载后
1.)在cmd中使用“ npm install”安装项目
2.)“ npm start”启动您的React应用

注意:您需要Node js软件才能在Windows中运行。 Mac OS具有默认节点。

欢呼

答案 44 :(得分:0)

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

配置您的 webpack.config.js ,以期望给定链接具有这种路由。

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

答案 45 :(得分:0)

我喜欢这种处理方式。尝试添加: 在服务器端 yourSPAPageRoute / * 可以解决此问题。

之所以采用这种方法,是因为就算是原生HTML5历史记录API也不支持页面刷新时进行正确的重定向(据我所知)。

注意:选定的答案已经解决了这个问题,但我正在尝试更具体。

Express Route

Test - History API 经过测试,只想分享。

希望有帮助。

答案 46 :(得分:0)

我遇到了同样的问题,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!');
});

答案 47 :(得分:0)

使用preact-router

进行Preact的解决方案

适用于刷新和直接访问

对于那些通过Google发现这一点的人来说,这里是preact-router + hash历史的演示:

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

https://jsfiddle.net/developit/gLyL6rbn/

答案 48 :(得分:0)

对于那些使用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页面,因为没有可用页面。执行以下操作:

  1. 打开IIS
  2. 展开服务器,然后打开“站点文件夹”
  3. 点击网站/应用程序
  4. 转到错误页面
  5. 打开列表中的404错误状态项
  6. 而不是选项&#34;将静态文件中的内容插入错误响应&#34;,将其更改为&#34;在此站点上执行URL&#34;并添加&#34; /&#34;将值减少到URL。
  7. 它现在可以正常工作了。

    enter image description here enter image description here

    我希望它有所帮助。 : - )

答案 49 :(得分:-1)

当你得到刷新dom组件后无法获得403错误时非常简单。只需在您的web pack配置中添加这一行,'historyApiFallback:true'。这节省了我一整天。