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

当前回答

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

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

When you hit refresh, you bypass all of the React and React Router code. The server gets the request for /joblist and it must return something. On the server you need to pass the path that was requested to the run method in order for it to render the correct view. You can use the same route map, but you'll probably need a different call to Router.run. As Charles points out, you can use URL rewriting to handle this. Another option is to use a Node.js server to handle all requests and pass the path value as the location argument.

例如,在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 });
    });
});

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

其他回答

如果你正在使用nginx托管,需要快速修复…

在你的nginx配置中添加以下代码:

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

在index.html文件头部,添加以下内容:

<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是重要的部分

对于使用iis10的用户,您应该这样做来纠正错误。

确保你使用了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中添加“/”斜杠值。

现在可以正常工作了。

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

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

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

我的主要JSX内容包括:

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

这对于第一个匹配的链接很有效,但是当嵌套在该模型的详细页面上的< link >表达式中的:id发生变化时,浏览器栏中的URL会发生变化,但页面的内容最初并没有改变以反映链接的模型。

问题是我已经使用props.params.id在componentDidMount中设置了模型。组件只挂载一次,因此这意味着第一个模型是粘贴在页面上的模型,随后的链接更改了道具,但保持页面看起来不变。

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