zoukankan      html  css  js  c++  java
  • vue-router路径计算问题

    简书原文

    昨天刚刚发表了一个前端跨域新方案尝试,今天在开发中就遇到的了问题。

    起因

    前端使用的是vue-router组件的history模式,但是由于我们的整个页面都是从static(静态资源站)load过来的,所以其他页面自然也需要跨域去拿,然而就在跨域的时候 vue-router 出了问题。

    分析问题

    我们的api站点在 api.com
    而静态资源在 static.com,页面的base标签也指向static

    <base href="http://static.com" />
    

    然而,在访问 test模板时却跳到了http://api.com/http:/static.com/test

    经过一些简单的断点调试,锁定了以下代码
    [source]: https://github.com/vuejs/vue-router/blob/dev/dist/vue-router.esm.js
    [vue-router.esm.js][source]

    //1794行~1675行
    function normalizeBase (base) {
      if (!base) {
        if (inBrowser) {
          // respect <base> tag
          var baseEl = document.querySelector('base');
          base = (baseEl && baseEl.getAttribute('href')) || '/';
        } else {
          base = '/';
        }
      }
      // make sure there's the starting slash
      if (base.charAt(0) !== '/') {
        base = '/' + base;
      }
      // remove trailing slash
      return base.replace(//$/, '')
    }
    

    这段代码的作用是设置路由的base路径,如果有兴趣一路跟踪的话会发现这个base参数是由实例化VueRouter 时候传入的options.base

    再看代码,他会判断如果base是空的,那么就会给一个默认值:
    如果实在浏览器(非服务器环境)下执行,那么会调用document.querySelector('base')来尝试获取<base href='' />标签中href属性的值;

    在我们实际的场景中,这里得到一个跨域的绝对地址,然后紧接着

      if (base.charAt(0) !== '/') {
        base = '/' + base;
      }
    

    当url第一个字符不是/的时候加上/,这里非常明显是一个BUG

    我的是绝对地址http://static.com第一个字符当然不是/
    所以才会由之前的http://api.com/http:/static.com/test这样的网址

    修改

    if(/^([a-z]+:)?///i.test(base)){
    
    }else if (base.charAt(0) !== '/') {
      base = '/' + base;
    }
    

    为了尽量少破坏源码,这里加了一个空的if,当url是由协议开始时,认为是绝对路径
    * 绝对路径还有一种形式是 //static.com

    测试

    经过第一次修改,再次访问页面依然有问题,访问的页面依然是http://api.com/http:/static.com/test

    继续分析

    再次跟踪源码后发现
    [vue-router.esm.js][source]

    //2006行~2016行
      HTML5History.prototype.push = function push (location, onComplete, onAbort) {
        var this$1 = this;
    
        var ref = this;
        var fromRoute = ref.current;
        this.transitionTo(location, function (route) {
          pushState(cleanPath(this$1.base + route.fullPath));
          handleScroll(this$1.router, route, fromRoute, false);
          onComplete && onComplete(route);
        }, onAbort);
      };
    //561行~563行
    function cleanPath (path) {
      return path.replace(////g, '/')
    }
    

    在发生pushState之前,他还会对url再次进行处理cleanPath
    而这里的处理更简单,更粗暴,问题也更大。

    他直接将2个斜杠//替换为1个斜杠/,话说如果连续3个斜杠怎么办?

    所以在处理http://static.com/test地址的时候,其实会被处理成http:/static.com/test 又变成相对路径了...

    继续修改

    function cleanPath (path) {
        var ishttp = /^([a-z]+:)?///i.exec(path);
        var http = Array.isArray(ishttp) ? ishttp[0] : '';
        return http + path.substr(http.length).replace(//{2,}/g, '/');
    }
    

    如果是协议开始,则排除协议内容之后,将2个或2个以上连续在一起的斜杠替换为1个斜杠。

    ** 完成提交pull
    https://github.com/vuejs/vue-router/pull/1353/files
    话说vue-router的url处理比起Url.js来说真的是太粗暴了...

  • 相关阅读:
    fullCalendar改造计划之带农历节气节假日的万年历(转)
    Linked List Cycle
    Remove Nth Node From End of List
    Binary Tree Inorder Traversal
    Unique Binary Search Trees
    Binary Tree Level Order Traversal
    Binary Tree Level Order Traversal II
    Plus One
    Remove Duplicates from Sorted List
    Merge Two Sorted Lists
  • 原文地址:https://www.cnblogs.com/blqw/p/6751622.html
Copyright © 2011-2022 走看看