vue-router路徑計算問題

簡書原文html

昨天剛剛發表了一個前端跨域新方案嘗試,今天在開發中就遇到的了問題。前端

原由

前端使用的是vue-router組件的history模式,可是因爲咱們的整個頁面都是從static(靜態資源站)load過來的,因此其餘頁面天然也須要跨域去拿,然而就在跨域的時候 vue-router 出了問題。vue

分析問題

咱們的api站點在 api.com
而靜態資源在 static.com,頁面的base標籤也指向staticgit

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

然而,在訪問 test模板時卻跳到了http://api.com/http:/static.com/testgithub

通過一些簡單的斷點調試,鎖定了如下代碼
[source]: https://github.com/vuejs/vue-router/blob/dev/dist/vue-router.esm.js
[vue-router.esm.js][source]vue-router

//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.baseapi

再看代碼,他會判斷若是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來講真的是太粗暴了...

相關文章
相關標籤/搜索