我正在使用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);
});
在后端使用Express.js,在前端使用React(没有React -create-app)和reach/router,正确的reach/router路由React组件会显示出来,当在地址栏中点击Enter时,菜单链接将被设置为活动样式,例如http://localhost:8050/pages。
请签出以下内容,或直接访问我的存储库https://github.com/nickjohngray/staticbackeditor。所有的代码都在那里。
网络包:
设置代理。这允许任何从端口3000 (React)调用服务器,
包括当按下回车键时在地址栏中获取index.html或任何东西的调用。它还允许调用API路由来获取JSON数据。
比如await axios。Post ('/api/login', {email, pwd}):
devServer: {
port: 3000,
open: true,
proxy: {
'/': 'http://localhost:8050',
}
}
设置Express.js路由
app.get('*', (req, res) => {
console.log('sending index.html')
res.sendFile(path.resolve('dist', 'index.html'))
});
这将匹配React的任何请求。它只返回dist文件夹中的index.html页面。当然,这个页面有一个更单页的React应用程序。(注意任何其他路由都应该出现在这个上面,在我的情况下,这些是我的API路由。)
反应路线
<Router>
<Home path="/" />
<Pages path="pages"/>
<ErrorPage path="error"/>
<Products path="products"/>
<NotFound default />
</Router>
这些路由是在我的布局组件中定义的,当路径匹配时,该组件将加载相应的组件。
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>
如果试图从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>
除了网络。配置文件,React应用程序本身需要一些改变:
在文件包中。Json,你需要添加一个'主页'条目:
{
"name": "sicon.react.crm",
"version": "0.1.0",
"private": true,
"homepage": "/YOURVIRTUALDIRECTORYNAME/",
"dependencies": {
...
我将basename添加到我的浏览器历史对象中,并将其传递给路由器以访问历史:
import {createBrowserHistory } from 'history';
export default createBrowserHistory({
//Pass the public URL as the base name for the router basename: process.env.PUBLIC_URL
});
我还在我的React路由器文件App.js中添加了这个属性:
<Router history={history} basename={process.env.PUBLIC_URL}>
最后,在index.html文件中,我在'title'标签上方添加了以下选项卡:
<base href="%PUBLIC_URL%/">
也许有些步骤是不需要的,但这似乎已经完成了我的工作。我不知道如何设置它运行在一个站点的根目录或虚拟目录,而不需要重新编译,作为包中的主页。据我所知,json不能在构建后交换。
我刚刚用Create React App做了一个网站,也遇到了同样的问题。
我使用react-router-dom包中的BrowserRouting。我在Nginx服务器上运行,添加以下到/etc/nginx/yourconfig.conf为我解决了这个问题:
location / {
if (!-e $request_filename){
rewrite ^(.*)$ /index.html break;
}
}
如果你正在运行Apache,这对应于在.htaccess中添加以下内容:
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
这似乎也是Facebook自己提出的解决方案。
这里有一个简单、清晰和更好的解决方案。如果你使用网络服务器,它就可以工作。
每个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页面发送回用户
那么JavaScript将在客户端完成剩下的工作,因为客户端的URL仍然是http://example.com/about。
就是这样。不再需要魔法:)