纯前端解决history router的问题

829 阅读2分钟

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处理的过程:

  1. 刷新/route
  2. 浏览器访问/route
  3. webpack-dev-server监听到后返回到/
  4. 此时返回/对应的index.html页面
  5. 开始请求index.html里的静态资源
  6. 不妙的事情来了,index.html里的静态资源bundle是相对路径bundle_xxx,那这时候请求到了/route/bundle_xxx
  7. 浏览器正常处理/route/bundle_xxx,继续请求我们的服务器dev server
  8. webpack_dev_server/route/bundle_xxx,又把这个路径定向给了/
  9. 此时返回/对应的index.html
  10. 此时/route/bundle_xxx返回了index.html
  11. 很明显,一个bundle包肯定是js文件,此时返回了html文件,自然就报错了。

问题解决

知道了问题的所在,我们解决问题就太轻松了。

问题在于第六步,我们的bundle文件打包出来是基于相对路径的,如果我们把它改为绝对路径就完全ok了呀。

解决办法

  • dev: 修改webpackpublicPath/即可
  • prod: 修改publicPath为对应的部署前缀即可

此时我们用纯前端的方式解决了Uncaught SyntaxError: Unexpected token '<'问题,再也不用去后端配置一个返回index.html的api了。

router

另外,如果你想要了解spa应用路由的原理,或者不想使用react-router这样庞大体量的路由库,可以参考一下 bobo-router 这是一个纯hooks,支持路由守卫的高性能匹配库。