histroy路由模式后续之connect-histroy-api-fallback源码精讲

181 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情

前情提要

上篇文章讲了关于vue或者react的项目使用了history模式之后页面刷新或者手工输入地址然后回车或者输入不存在的路由的时候出现404的情况的两种解决办法。针对第一种关于nginx的配置的问题没有什么过多的可以讲的。但是关于connect-histroy-api-fallback插件我们到可以深入源码看看到底是怎么实现的。

出现的原因

究其原因是因为浏览器识别到了不属于该项目的地址或者刷新页面初始化的时候,就会发起向该地址的get请求,请求页面相关文件信息,然后才导致了404的情况。

connect-histroy-api-fallback的实现原理

  • 先删掉关于打的logger的代码,然后就能很清晰的看明白了。
  • 具体思路:
    1. 首先劫持到请求后,会先对请求的类型进行判断,如果不是GET请求,那么直接放过,执行next()方法。
      • 解释:此举主要是因为浏览器发起的页面请求一定是GET请求。
    2. 如果是GET请求,那么继续判断该请求的请求头是否为false或者请求头中的accept的类型不为string。两者条件满足一个则放过请求,它不是我们要拦截处理的请求。只有当请求头存在并且accept的类型为string的时候它才有可能是我们要拦截处理的请求。
      • 解释
        • accept是浏览器告诉服务器它想接收的数据的类型。比如:text/html(html文本);text/plain(纯文本格式);text/xml(xml格式);等等还有很多。
        • 此举只为确保该请求为我们需要拦截处理的携带正常请求头信息的请求。
    3. 上面的条件没有满足,那说明请求头存在并且accept为string类型。那么此时就判断该请求头中的accept是否包含类型:application/json并且在accept中的位置为首位。如果不是则有可能是我们的目标请求。如果是放开,因为这不是我们的目标请求。
      • 解释:此举主要是因为基本上常规的接口请求的accept的首位格式都是:application/json
    4. 最后会调用一个封装好的方法:acceptsHtml,根据返回值是true还是false来决定是放开还是继续向下执行。
    5. acceptsHtml里的思路是:
      • 接受两个参数,第一个是请求头中的accept,第二个是初始化该插件时传过来的options对象。
      • 然后初始化options中的htmlAcceptHeader,如果初始化插件的时候有传则用传过来的,如果没有则设置默认值:['text/html', '*/*'].
      • 之后遍历htmlAcceptHeader数组,如果请求的accept中包含任意一项则直接返回true,放开该请求。如果accept都不包含htmlAcceptHeader中的元素,则继续进行。
        • 此举主要是针对特殊的情况所放开的一个拓展。
    6. 上面的重重关卡都通过之后,那么下面便来到了最关键的地方。此时该请求便是我们需要拦截处理的请求了。
      • 首先通过node的url模块先parse再获取其他url。
      • 其次初始化重写规则变量声明。以及初始化插件初始化时传入的重写规则,如果没有传入则默认为空数组。
      • 之后对该数组进行遍历,如果为空则直接进行下面的代码。
        • 如果不为空,也就是开发者预设置了重写规则。那么:
        • 会对开发者预设值的重写规则进行遍历校验,如果预设值对象的from的值与我们获取到的请求url不一致,则直接进行下一步。
        • 如果一致,则会校验重写规则,规则中如果rule不是function类型则会抛出异常。如果是string类型的则直接将该rule返回。否则返回一个rule对象。
        • 然后会将请求的url设置成校验重写规则方法返回的值。此时请求路径重写成功,最后再放开执行next就可以了。
      • 如果为空则将遇到真正的最后一道关卡。此时获取到请求url中的pathname,如果pathname中的 . 的位置比 ‘/’ 的位置长,并且用户选择了禁用点规则。两个都满足了则表明不是我们要的请求,放开。有任意一个不满足,便是我们最终要找的人
      • 此时会先获取插件初始化时用户填写的index配置项,如果没有则默认为:’/index.html‘
      • 最后将请求的url替换成我们重新修改后的路径。再放开就大工告成了。

总结

  • 上面便是插件的总体实现思路了。
  • 大的方向就是拦截浏览器发起的请求页面的请求,然后改写他的请求路径为默认的单页面应用的文件地址。
  • 该插件还为用户提供了几个可选的配置:
    • index: 单页面文件名,比如:default.html。不写的话默认为index.html
    • rewrite: 重写规则,接受一个对象。包含:from和to两个属性
    • disableDotRule:是否允许点规则。接收一个布尔值
    • htmlAcceptHeaders: 接受一个数组,会对拦截的请求的accept进行匹配,匹配到则是我们要拦截处理的请求。
    • logger:主要是打log用的。用户可自己传入自己自定义的打log的方法
    • verbose: 是否激活日志。与上面的logger二者有一即可。
  • 该插件同样适用koa2框架...
  • 源码截图:(建议删除logger方法,会更有助于你理解)

WX20220616-005227@2x.png