一文讲通该用encodeURI还是encodeURIComponent

168 阅读2分钟

首先你要用这两个函数的时候,大概率是准备把一些参数拼成url。

把参数拼成url之后,大概率要在另外的页面,把url字符串解析为参数,然后做一系列的操作。

我们先从解析说起,大概率你是面对着这样的形式:?foo=123&bar=456&name=789

要把这个字符串转换成可用的参数,其实很简单,首先去掉头部的?,然后字符串根据&split,得到类似foo=123bar=456的键值对,然后对这些键值对再根据=split,就能一一分离出key和value,小菜一碟,随便手撸。

但你想过没有,如果&=出现在不该出现的地方,是不是解析就全乱套了?

有点慌,于是我们去看看encodeURIencodeURIComponent对于&=的转义

encodeURI('&'); // &
encodeURI('='); // =
encodeURIComponent('&'); // %26
encodeURIComponent('='); // %3D

看到这个小实验结果,你隐隐约约有个猜想:如果值里面有&=字符,而没有用encodeURIComponent去转化的话,后面解析的时候很有可能得到错误的结果,因为出现了分隔符以外的&=

我们看这个完整的例子:

// 打算通过URL传递一个json字符串
var jsonStr = JSON.stringify({
  age: '18',
  name: '&Job',
  sex: '=alive',
}); 
// 传给页面是params=json字符串
var testStr1 = '?params=' + encodeURI(jsonStr); 
var testStr2 = '?params=' + encodeURIComponent(jsonStr);

// 把url字符串转为obj的函数,通过&和=去分隔
function searchToObj(search, decodeMethod) {
  var result = {};
  if (!search) return result;
  if (!decodeMethod) {
    decodeMethod = function(val) {
      return val;
    }
  }
  search = search.slice(1); // 把开头的?过滤掉
  var searchArr = search.split('&');
  searchArr.forEach(function(kvPair) {
    var kvArr = kvPair.split('=');
    result[kvArr[0]] = decodeMethod(kvArr[1])
  });
  return result;
}

// 解析还原传过来的参数
var decodeStr1 = searchToObj(testStr1);
var decodeStr2 = searchToObj(testStr2);

发现用encodeURIComponent解析还原的参数是:params: "%7B%22age%22%3A%2218%22%2C%22name%22%3A%22%26Job%22%2C%22sex%22%3A%22%3Dalive%22%7D",是对的

而用encodeURI解析还原的参数是:Job%22,%22sex%22:%22: "alive%22%7D"params: "%7B%22age%22:%2218%22,%22name%22:%22",莫名其妙多了个Job%22,%22sex%22:%22的键值对

结论:拼接url时请使用encodeURIComponent,以防止拼接内容中含有&=及其他未转义的字符,而导致难以预期的bug。