react-router 原理
react-router 是建立在 history 之上的,history 监听浏览器地址栏的变化,解析 URL 然后转换成 location 对象,然后 router 使用它匹配到路由,正确的渲染对应的页面。
browserHistory 原理
browserHistory 使用的是浏览器的 history api,创建一个真实的 URL。
browserHistory 需要进行服务器配置:
使用 browserHistory 需要服务器去配置处理 URL,处理启动最初的 /
是没有问题的,但是当路由来回跳转并且在某个路由上进行页面刷新时,服务器接收到来自某个路由的请求,需要处理这个 URL 并且在响应中包含 JavaScript 应用代码。
更多了解:https://react-guide.github.io/react-router-cn/docs/guides/basics/Histories.html
什么是 browserHistory,什么是 hashHistory
history 指的是如何去监听浏览器地址栏的变化
browserHistory 是 HTML5 提供的 History API,使用浏览器提供接口修改历史记录,浏览器上看到的 URL 是这样的:/user/haishanh
hashHistory 是 通过改变地址后面的 hash 来改变浏览器的历史记录,浏览器上看到的 URL 是这样的:/#/user/haishanh?_k=adseis
为什么使用 browserHistory 而不是 hashHistory
- 可以使用 pushState() 和 replaceState() 方法来增加或替换历史记录
- hash 部分并不会被浏览器发送到服务端,也就是说不管是请求 http://domain.com/index.html#foo 还是 http://domain.com/index.html#bar ,服务只知道请求了 index.html 并不知道 hash 部分的细节
- 某些情况会忽略 URL 中的 hash 部分,比如:将 URL 使用微信分享时会丢失 hash 部分
?_k=ckuvup
的作用是什么
当我们使用 window.location.hash = newHash 进行 hash history 跳转时,我们想要全部的 history 都能够使用 location state。
我们就为每一个 location 创建一个唯一的 key,把它们的状态存储在 session storage 中,当访客点击“后退”和“前进”时,我们就会有一个机制去恢复这些 location state。
解决方案:webpack-dev-server 中设置
当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.html
-
默认情况下,没有修改 output.publicPath 值
devServer: { historyApiFallback: true; }
-
修改了 output.publicPath 值
// output.publicPath: '/assets/' devServer: { historyApiFallback: { index: "/assets/"; } }
官方介绍:https://webpack.docschina.org/configuration/dev-server/#devserver-historyapifallback
browserHistory 的服务器端的配置
BrowserRouter:路由不通过 Hash 完成,显示正常的路径 example.com/some/path
,背后调用的是浏览器的 History API。
服务器改造:BrowserRouter 相当于直接向服务器请求某个子路由,会显示网页找不到的 404 错误。使用 webpack-dev-server
,加上 --history-api-fallback
参数
- webpack 配置
使用webpack-dev-server
,启动时加上--history-api-fallback
参数
或者在 webpack.config.js 文件中:
devServer: {
historyApiFallback: true;
}
- express 配置:
const express = require("express");
const path = require("path");
const port = process.env.PORT || 8080;
const app = express();
// 通常用于加载静态资源
app.use(express.static(__dirname + "/public"));
// 在你应用 JavaScript 文件中包含了一个 script 标签
// 的 index.html 中处理任何一个 route
app.get("*", function(request, response) {
response.sendFile(path.resolve(__dirname, "public", "index.html"));
});
app.listen(port);
console.log("server started on port " + port);
- nginx 配置:
server {
...
location / {
try_files $uri /index.html
}
}