Javascript 反应路由器URL don';刷新或手动写入时无法工作
我正在使用React路由器,当我点击链接按钮时,它工作正常,但当我刷新网页时,它不会加载我想要的内容 例如,我在Javascript 反应路由器URL don';刷新或手动写入时无法工作,javascript,reactjs,url,react-router,Javascript,Reactjs,Url,React Router,我正在使用React路由器,当我点击链接按钮时,它工作正常,但当我刷新网页时,它不会加载我想要的内容 例如,我在localhost/joblist中,一切都很好,因为我按了一个链接到达这里。但如果我刷新网页,我会得到: 无法获取/作业列表 默认情况下,它不是这样工作的。最初我的URL是localhost/#/和localhost/#/joblist,它们工作得非常好。但我不喜欢这种URL,所以试图删除它,我写道: Router.run(routes, Router.HistoryLocatio
localhost/joblist
中,一切都很好,因为我按了一个链接到达这里。但如果我刷新网页,我会得到:
无法获取/作业列表
默认情况下,它不是这样工作的。最初我的URL是localhost/#/
和localhost/#/joblist
,它们工作得非常好。但我不喜欢这种URL,所以试图删除它,我写道:
Router.run(routes, Router.HistoryLocation, function (Handler) {
React.render(<Handler/>, document.body);
});
路由器可以用两种不同的方式调用,这取决于导航是在客户机上进行还是在服务器上进行。您已将其配置为客户端操作。关键参数是位置的第二个参数 当您使用React Router链接组件时,它会阻止浏览器导航并调用Transitiono来执行客户端导航。您使用的是HistoryLocation,因此它使用HTML5历史API通过模拟地址栏中的新URL来完成导航的假象。如果您使用的是较旧的浏览器,这将不起作用。您需要使用HashLocation组件 当您点击刷新时,您将绕过所有React和React路由器代码。服务器获取对
/joblist
的请求,它必须返回一些内容。在服务器上,您需要将请求的路径传递给run
方法,以便它呈现正确的视图。您可以使用相同的路线图,但可能需要对路由器进行不同的调用。运行。正如Charles指出的,您可以使用URL重写来处理这个问题。另一个选项是使用node.js服务器处理所有请求,并将path值作为location参数传递
例如,在express中,它可能如下所示:
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。路由器可以通过两种不同的方式调用,具体取决于导航是在客户端还是在服务器上进行。您已将其配置为客户端操作。关键参数是位置的第二个参数
当您使用React Router链接组件时,它会阻止浏览器导航并调用Transitiono来执行客户端导航。您使用的是HistoryLocation,因此它使用HTML5历史API通过模拟地址栏中的新URL来完成导航的假象。如果您使用的是较旧的浏览器,这将不起作用。您需要使用HashLocation组件
当您点击刷新时,您将绕过所有React和React路由器代码。服务器获取对/joblist
的请求,它必须返回一些内容。在服务器上,您需要将请求的路径传递给run
方法,以便它呈现正确的视图。您可以使用相同的路线图,但可能需要对路由器进行不同的调用。运行。正如Charles指出的,您可以使用URL重写来处理这个问题。另一个选项是使用node.js服务器处理所有请求,并将path值作为location参数传递
例如,在express中,它可能如下所示:
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。查看对已接受答案的评论以及此问题的一般性质(“不起作用”),我认为这可能是一个对这里涉及的问题进行一般性解释的好地方。因此,这个答案旨在作为OP特定用例的背景信息/详细说明。请接受我的回答
服务器端与客户端
关于这一点,首先要了解的是,现在有2个地方可以解释URL,而在“旧时代”中只有1个。在过去,当生活很简单的时候,一些用户发送了一个http://example.com/about
发送到服务器,服务器检查URL的路径部分,确定用户正在请求关于页面,然后将该页面发回
使用React路由器提供的客户端路由,事情就不那么简单了。首先,客户端还没有加载任何JS代码。因此,第一个请求总是发送到服务器。然后,它将返回一个页面,其中包含加载React和React Router等所需的脚本标记。只有当这些脚本已加载时,阶段2才会启动。在第2阶段,例如,当用户单击“关于我们”导航链接时,URL仅在本地更改为http://example.com/about
(由提供),但未向服务器发出请求。相反,React Router在客户端执行其操作,确定要渲染的React视图,并对其进行渲染。假设您的about页面不需要进行任何REST调用,那么它已经完成了。您已从家中转到About Us,但未触发任何服务器请求
因此,基本上,当您单击一个链接时,会运行一些Javascript来操纵地址栏中的URL,而不会导致页面刷新,从而导致React Router在客户端执行页面转换
但是现在考虑一下如果复制粘贴地址栏中的URL会发生什么
<script>
System.config({ baseURL: '/' });
</script>
devServer: {
historyApiFallback: true,
contentBase: './',
hot: true
},
<Route onEnter={requireLogin} path="detail/:id" component={ModelDetail} />
<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>
<?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>
<Router history={hashHistory} >
<Route path="/home" component={Home} />
<Route path="/aboutus" component={AboutUs} />
</Router>
sudo npm run build
<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>
cd /etc/apache2/sites-available
sudo a2ensite sample.conf
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^.*$ / [L,QSA]
<Router history={hashHistory} >
import { HashRouter } from 'react-router-dom'
<HashRouter>
<App/>
</HashRouter>
<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>
/* /index.html 200
// app.js
import { BrowserRouter as Router } from 'react-router-dom'
const App = () {
render() {
return (
<Router>
// your routes here
</Router>
)
}
}
// 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)
}
})
})
location / {
try_files $uri /index.html;
}
location / {
if (!-e $request_filename){
rewrite ^(.*)$ /index.html break;
}
}
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
devServer: {
historyApiFallback: true
}
<?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>
<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');
});
expressApp.get('/*', (request, response) => {
response.sendFile(path.join(__dirname, '../public/index.html'));
});
<base href="/">
<!-- This must come before the css and javascripts -->
webpack-dev-server --mode development --hot --inline --content-base=dist --history-api-fallback
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"));
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
RewriteRule ^ /index.html [L]
{
"hosting": {
"rewrites": [{
"source":"**",
"destination": "/index.html"
}]
}
}
module.exports = {
entry: './app/index.js',
output: {
path: path.join(__dirname, '/bundle'),
filename: 'index_bundle.js',
publicPath: '/'
},
<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>
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");
}
}
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
"start": "webpack-dev-server --inline --content-base . --history-api-fallback"
@Controller
public class ForwardingController {
@RequestMapping("/<any end point name>/{path:[^\\.]+}/**")
public String forward(HttpServletRequest httpServletRequest) {
return "forward:/";
}
}
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();
<?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>
{
"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
});
<Router history={history} basename={process.env.PUBLIC_URL}>
<base href="%PUBLIC_URL%/">