histroy router的问题
在history router
模式下,我们可能会进行一些刷新路由操作
场景复现如下:
我们的路由位于/route
之下,此时进行刷新。
不巧,我们出现404了。
这个问题很简单,因为没有对应的api或者静态资源,所以很正常的返回了404页面。
此时你不想添加一个后端api返回全局index.html,所以通过了webpack-dev-server的historyFallback
进行了重定向兜底。
此时再次刷新:
不巧,我们的刷新没有成功,报错了:
Uncaught SyntaxError: Unexpected token '<'
点开错误详情,发现第一行error
<!DOCTYPE html>
再看一下请求,不是应该返回script
吗,怎么返回了一个html
了?
问题剖析
原来是我们通过webpack-dev-server
里的historyfallback
进行了一次兜底,把所有的页面通通返回到/
。
这本来是一件好事,它可以让任何请求都返回/
页面(也就是我们的index.html),然后走我们react的router逻辑,再分发到对应的页面。
但是问题就出在这里,我们复现一下浏览器和webpack处理的过程:
- 刷新
/route
- 浏览器访问
/route
webpack-dev-server
监听到后返回到/
。- 此时返回
/
对应的index.html
页面 - 开始请求
index.html
里的静态资源 - 不妙的事情来了,
index.html
里的静态资源bundle是相对路径bundle_xxx
,那这时候请求到了/route/bundle_xxx
- 浏览器正常处理
/route/bundle_xxx
,继续请求我们的服务器dev server webpack_dev_server
把/route/bundle_xxx
,又把这个路径定向给了/
- 此时返回
/
对应的index.html
- 此时
/route/bundle_xxx
返回了index.html
- 很明显,一个bundle包肯定是js文件,此时返回了html文件,自然就报错了。
问题解决
知道了问题的所在,我们解决问题就太轻松了。
问题在于第六步,我们的bundle
文件打包出来是基于相对路径的,如果我们把它改为绝对路径就完全ok了呀。
解决办法
- dev: 修改
webpack
的publicPath
为/
即可 - prod: 修改
publicPath
为对应的部署前缀即可
此时我们用纯前端的方式解决了Uncaught SyntaxError: Unexpected token '<'
问题,再也不用去后端配置一个返回index.html
的api了。
router
另外,如果你想要了解spa
应用路由的原理,或者不想使用react-router
这样庞大体量的路由库,可以参考一下
bobo-router
这是一个纯hooks,支持路由守卫的高性能匹配库。