url编码解码,多次编解码问题

2,219 阅读7分钟

文章转自csdn[weixin_39918248] # 如何判断字符串已经被url编码_前端面试题(三) 如何解码一个被编码了不知道多少次的url地址...

防止以后链接失效,将文章copy下来,向原创作者【畅哥聊技术】致敬

话不多说上代码:

var url = 'https://www.baidu.com?a=xxx&b=12&c=水电费、#的'
console.log('编码前',url)
var url2 =encodeURIComponent(url)
console.log('编码1',url2)
url2 =encodeURIComponent(url2)
console.log('编码2',url2)
url2 =encodeURIComponent(url2)
console.log('编码3',url2)

console.log('解码前:',url2)
let url3 = decodeURIComponent(url2)
console.log('解码1后:',url3)
url3 = decodeURIComponent(url3)
console.log('解码2后:',url3)
url3 = decodeURIComponent(url3)
console.log('解码3后:',url3)

/**
 * 解码URl 解码一个被编码N次的url
 * @param url
 * @returns
 */
export const decoeUrl = (uri) => {
    if(decodeURIComponent(uri)===uri){
      return uri
    }else{
      return arguments.callee(decodeURIComponent(uri))
    }
}

原文内容

如何判断字符串已经被url编码_前端面试题(三) 如何解码一个被编码了不知道多少次的url地址...

1.url编码和解码

这里面有一个坑,我掉进去了,我先说通过encodeURI来编码,decodeURI来解码。我话音刚落,面试官断了我说:你确定吗?

突然的打断让我有些不知所措,导致接下来的面试都不顺利。

我的大脑高速旋转,然后我想到了之前做微信分享的时候,我们传入url的时候需要将地址进行编码,那个好像用不是这个encodeURI,没错,是 encodeURIComponent 这个API,虽然我没有完整的将这个单词说出来,然后我结合业务场景,说出了url编码的一个应用,也算是勉强过关了吧。

说完了以后,面试官说:encodeURI和decodeURI已经不再建议使用了。转而我们应该使用encodeURIComponentdncodeURIComponent来替代。

这个应该只是前戏了,关键是这个题目的本身该如何去解?

不着急解题,我们先来看看这两个api的基本用法。

7d31ea02ce97a76344c1af69a7e4c9b9.gif 编码后,程序会将我们的url中的特殊字符进行编码,生成一个新的url,如果继续编码,将会继续生成一个不同的url。

同理,我们再来看下解码过程。

5d7a88ab469bafe03cd0ab2905998930_a75642a95dd5da274513a3440b287bc7.gif 我们将之前编码后的url进行两次解码,可以得到我们最终熟悉的url了。

好了,我们再来回到问题本身。如何解码一个被多次编码的url.也就是说,这个url我们是不知道它被编码了多少次的。

那这个问题该怎么解呢?

第一次面临这样的问题,在面试的过程中可能一下子被问住了。没关系,我们先来看另一个问题。

说:如果遍历一个文件夹中的文件夹和文件。相信这个问题很直白了。文件夹里面可能还有文件夹,里面可以无限嵌套。

其实稍微有些工作经验的就知道,文件夹的问题肯定是要用到递归来处理了。

好,我们再来类比一下我们的今天的这个问题。两个问题有什么相同的地方没有?

解题思路

不难发现,两个问题中,有一个共同的特点。那就是都有一个不确定的因素。不知道文件夹有多少层,不知道url被编码了多少次。

从类比结果我们可以知道,这个url编码的问题应该是要用到递归算法去处理了。

递归算法

关系递归算法的相关知识点,我前面的文章函数那点事已经有了详细的介绍,这里不再赘述了。 首先,我们找出终止条件。

如果一个url解码前和解码后的不发生任何变化,那么我们就可以判断这个url被完全编码出来了。

6d8b51148e5488bdd1181bac9dcebf56_401605b0e27b964572633ae3e5f2e37c.gif

找出了终止条件,接下来我们调用自身的方法,我只需要将编码后的参数继续调用自身去编码即可。

好了,到这这个问题基本上可以解决掉了。

下面我来上完整的代码的结果

358de8fc1ef9a6989f88686e87dca08f_3814862fb914bceb3ac9bc243a7d7398.gif 好了,到这里,这个问题基本是可以是解决了。

总结:

  • url编码和解码用到的新的api。
  • 在面试过程中,凡是提到了不知道有多少次操作的,一般来说都要用到递归算法。
  • 递归算法的核心技巧可以参考我前面的文章,这一点很重要,面试非常喜欢问。

最后给大家留一个真实的面试题,也是有关递归算法的。

将一个数组扁平化

var arr = [1,[2,3,[4,5]],[6,7,8,[9]]];

给出一个算法,让返回数组结果:[1,2,3,4,5,6,7,8,9];

这个题目就很直白了,一般来说我们知道用递归算法了。


文章转自csdn[weixin_39918248] # 如何判断字符串已经被url编码_前端面试题(三) 如何解码一个被编码了不知道多少次的url地址...

防止以后链接失效,将文章copy下来,向原创作者【畅哥聊技术】致敬

测试代码

var url =  'https://www.baidu.com?a=xxx&b=12&c=水电费、#的&&d=123'
console.log('编码前',url)
var url2 =encodeURIComponent(url)
console.log('编码1',url2)
url2 =encodeURIComponent(url2)
console.log('编码2',url2)
url2 =encodeURIComponent(url2)
console.log('编码3',url2)
console.log('编码后源url',url)
console.log('解码前:',url2)
let url3 = decodeURIComponent(url2)
console.log('解码1后:',url3)
url3 = decodeURIComponent(url3)
console.log('解码2后:',url3)
url3 = decodeURIComponent(url3)
console.log('解码3后:',url3)
VM1187:2 编码前 https://www.baidu.com?a=xxx&b=12&c=水电费、#的&&d=123
VM1187:4 编码1 https%3A%2F%2Fwww.baidu.com%3Fa%3Dxxx%26b%3D12%26c%3D%E6%B0%B4%E7%94%B5%E8%B4%B9%E3%80%81%23%E7%9A%84%26%26d%3D123
VM1187:6 编码2 https%253A%252F%252Fwww.baidu.com%253Fa%253Dxxx%2526b%253D12%2526c%253D%25E6%25B0%25B4%25E7%2594%25B5%25E8%25B4%25B9%25E3%2580%2581%2523%25E7%259A%2584%2526%2526d%253D123
VM1187:8 编码3 https%25253A%25252F%25252Fwww.baidu.com%25253Fa%25253Dxxx%252526b%25253D12%252526c%25253D%2525E6%2525B0%2525B4%2525E7%252594%2525B5%2525E8%2525B4%2525B9%2525E3%252580%252581%252523%2525E7%25259A%252584%252526%252526d%25253D123
VM1187:9 编码后源url https://www.baidu.com?a=xxx&b=12&c=水电费、#的&&d=123
VM1187:10 解码前: https%25253A%25252F%25252Fwww.baidu.com%25253Fa%25253Dxxx%252526b%25253D12%252526c%25253D%2525E6%2525B0%2525B4%2525E7%252594%2525B5%2525E8%2525B4%2525B9%2525E3%252580%252581%252523%2525E7%25259A%252584%252526%252526d%25253D123
VM1187:12 解码1后: https%253A%252F%252Fwww.baidu.com%253Fa%253Dxxx%2526b%253D12%2526c%253D%25E6%25B0%25B4%25E7%2594%25B5%25E8%25B4%25B9%25E3%2580%2581%2523%25E7%259A%2584%2526%2526d%253D123
VM1187:14 解码2后: https%3A%2F%2Fwww.baidu.com%3Fa%3Dxxx%26b%3D12%26c%3D%E6%B0%B4%E7%94%B5%E8%B4%B9%E3%80%81%23%E7%9A%84%26%26d%3D123
VM1187:16 解码3后: https://www.baidu.com?a=xxx&b=12&c=水电费、#的&&d=123

前端JS获取URL参数的4种方法总结

1.【推荐】使用第三方库 qs

使用第三方库 qs 也可以实现 url 中参数字符的提取,还能实现将参数对象转为 url 参数形式,需要注意的是浏览器 cdn 方式引入时是默认添加到全局对象 windowQs 属性上的,或者import 引入
<script src="https://cdn.bootcdn.net/ajax/libs/qs/6.10.3/qs.min.js"></script>
<script>
let URL = "http://www.baidu.com?product='iPhone 13 Pro'&price=¥9999.00"
function getUrlParams4(url){
	// 引入 qs 库时会默认挂在到全局 window 的 Qs 属性上
	// console.log(window)
	let urlStr = url.split('?')[1]
	let result = Qs.parse(urlStr)
	// 拼接额外参数
	let otherParams = {
		num:50,
		size:6.1
	}
	let str = Qs.stringify(otherParams)
	let newUrl = url + str
	return {result,newUrl}
}
console.log(getUrlParams4(URL))
</script>

2.方法1: 字符串 split 方法

因为一个 url 地址是字符串形式的,所以利用 split 方法将参数提取出来,该方法比较常用,而且容易理解
let URL = "http://www.baidu.com?name=张三&age=25&sex=男&wife=小红"
function getUrlParams(url) {
    // 通过 ? 分割获取后面的参数字符串
    let urlStr = url.split('?')[1]
    // 创建空对象存储参数
	let obj = {};
    // 再通过 & 将每一个参数单独分割出来
	let paramsArr = urlStr.split('&')
	for(let i = 0,len = paramsArr.length;i < len;i++){
        // 再通过 = 将每一个参数分割为 key:value 的形式
		let arr = paramsArr[i].split('=')
		obj[arr[0]] = arr[1];
	}
	return obj
}
console.log(getUrlParams(URL))

3. 利用正则匹配方法

正则匹配功能强大相信很多小伙伴都知道,不仅可以实现在登录注册时的账号、密码、邮箱、手机号等等的验证,还可以非常方便的处理一些字符串(校验、替换、提取等操作),难点在于对正则使用的熟练度,这里就是通过正则提取字符串中需要的字符
let URL = "http://www.baidu.com?name=Tom&friend=Jerry"
function getUrlParams3(url){
	// \w+ 表示匹配至少一个(数字、字母及下划线), [\u4e00-\u9fa5]+ 表示匹配至少一个中文字符
	let pattern = /(\w+|[\u4e00-\u9fa5]+)=(\w+|[\u4e00-\u9fa5]+)/ig;
	let result = {};
	url.replace(pattern, ($, $1, $2)=>{
		result[$1] = $2;
	})
	return result
}
console.log(getUrlParams3(URL))

4. 利用 URLSearchParams 方法

在 MDN 中结合两种方法实现参数的获取:1. 使用 `new URLSearchParams(url)` 方法,返回一个 URLSearchParams 对象,再调用 `entries()` 方法返回一个可迭代对象(Iterator);2. 使用 `Object.fromEntries(iterable)` 方法转化为普通对象
**特别注意 **:URLSearchParams 方法不仅可以获取参数,还可以将参数对象转为 字符串,详细用法可查看 MDN 中的介绍,并且该方法存在浏览器兼容性问题。
let URL = "http://www.baidu.com?name=Jack&age=25&sex=men&wife=Lucy"
function getUrlParams2(url) {
	let urlStr = url.split('?')[1]
	const urlSearchParams = new URLSearchParams(urlStr)
	const result = Object.fromEntries(urlSearchParams.entries())
	return result
}
console.log(getUrlParams2(URL))