乐趣区

关于html:如何在一段URL中插入参数

有一个很简略的需要如下:

给你一段 URL,在其中插入一些参数,并返回新的 URL,如何实现?

这里的参数,有时候称为query,有时候称为params,个别称为search,指的是

http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument

中的 key1key2

最近正在对接阿里云的金融级实人认证,在传递认证胜利回调页时就遇到了这样一个问题。

第一层:间接拼

import qs from 'query-string'
function resolve (url) {const params = qs.stringify({ a: 1, b: 2}) // a=1&b=2
  return url + '?' + params
}

理论业务中,90% 的场景这样写没问题,但如果 url 的值是这样的:

http://taobao.com/?c=3&d=4

最终后果就是

http://taobao.com/?c=3&d=4?a=1&b=2

将这段 URL 中的 search 解析,失去的后果是

{
  c: '3',
  d: '4?a=1',
  b: '2',
}

显然不合乎预期。

第二层:兼容已存在的 search

import qs from 'query-string'
function resolve (url) {const params = qs.stringify({ a: 1, b: 2}) // a=1&b=2
  return url + url.includes('?') ? '&' : '?' + params
}

看上去问题仿佛解决了,很多人也只思考到这一层,但当初还有这样一种 url:

http://taobao.com/#/xxx

尤其是单页利用,这个模式的 hash 路由十分常见。

如果只是简略地拼接到 URL 尾部:

http://taobao.com/#/xxx?a=1&b=2

将这段 URL 中的 search 解析,失去的后果是

{}

能够看到拼接的参数基本没跑到 search 外面去。

也就是说,只有 URL 中呈现了 #,这之后呈现的? 就不会被视作 search 的起始标记,而是 hash 的一部分。

如果 URL 再简单一点,比方:

http://taobao.com/?c=3&d=4#/xxx

下面的拼接会变成:

http://taobao.com/?c=3&d=4#/xxx&a=1&b=2

岂但没有依照预期插入参数,还毁坏了本来的 hash 构造。

实际上,以 vue-router 为例,它的路由零碎中恰好就用到了 hash 中的?

比方:

http://example.com/user/:foo/info?c=3&d=4#/xxx?a=1&b=2

在 vue-router 里,xxx是路由的 path,foo被称作 params,ab 被称作 query,别离能够通过
route.paramsroute.query获取。

#之后能够接任意字符串,?a=1&b=2只是路由本人定义的一套外部规定,为路由传参服务。

cd才是 search,须要从 location.search 中解析。

如果后端接管了这样一段 GET 申请,hash 前面的货色都会被摈弃,只有 search 能够被接管和解析。

因而,插入参数不能呈现在 # 之后,也就是说,简略地在 URL 前面拼接字符串是不行的。

第三层:只解决 search

import qs from 'query-string'
function resolve (url) {const params = qs.stringify({ a: 1, b: 2}) // a=1&b=2
  const urlObj = new URL(url)
  urlObj.search += urlObj.search.startsWith('?') ? '&' : '?' + params
  return urlObj.href
}

这样就能够解决下面的简单状况了。

应用 URL 对象是一个讨巧的方法,将 url 字符串解析为 URL 对象后,能够只批改它的 search 属性而不影响其余局部。

axios 的源码中,咱们能够看到另一种规范实现:

function buildURL(url, params) {if (!params) {return url;}
  
  // params 序列化过程略
  var hashmarkIndex = url.indexOf('#');
  if (hashmarkIndex !== -1) {url = url.slice(0, hashmarkIndex);  
  }
 
  url += (url.indexOf('?') === -1 ? '?' : '&') + params;

  return url;
};

思路很简略,就是把序列化后的 params 插入到 URL 的开端,但若存在 hash,则插到 hash 之前,若存在 search,则连接符改用&

相干链接:

What is a URL

URL 对象

Vue-router 路由对象

退出移动版