学习链接
【Q429】实现一个函数用来解析 URL 的 querystring
【Q440】实现一个函数用来对 URL 的 querystring 进行编码
解析 URL
URL 对象
new URL(url, [base])
**url**
—— 完整的 URL,或者仅路径(如果设置了 base),**base**
—— 可选的 base URL:如果设置了此参数,且参数url
只有路径,则会根据这个base
生成 URL。
let url = new URL('https://test.com/profile/user');
let newUrl1 = new URL('/tester', 'https://test.com/profile/user');
let newUrl2 = new URL('/tester', url);
let newUrl3 = new URL('/tester', 'https://test.com/profile/user'); //
let newUrl4 = new URL('/tester', 'https://test.com/profile/');
let newUrl5 = new URL('tester', 'https://test.com/profile/user');
let newUrl6 = new URL('tester', 'https://test.com/profile/');
let newUrl7 = new URL('//tester', 'https://test.com/profile/');
console.log('newUrl1.href: ', newUrl1.href); // https://test.com/tester
console.log('newUrl2.href: ', newUrl2.href); // https://test.com/tester
console.log('newUrl3.href: ', newUrl3.href); // https://test.com/tester
console.log('newUrl4.href: ', newUrl4.href); // https://test.com/tester
console.log('newUrl5.href: ', newUrl5.href); // https://test.com/profile/tester
console.log('newUrl6.href: ', newUrl6.href); // https://test.com/profile/tester
console.log('newUrl7.href: ', newUrl7.href); // https://tester/
自动编码,转换不合法字符。
(new URL('https://site.com/pat h')).href // 'https://site.com/pat%20h'
编码字符串
- encodeURI —— 编码整个 URL。
- decodeURI —— 解码为编码前的状态。
- encodeURIComponent —— 编码 URL 组件,例如搜索参数,或者 hash,或者 pathname。
- decodeURIComponent —— 解码为编码前的状态。
https://site.com:8080/path/page?p1=v1&p2=v2#hash
在 URL 中 :
,?
,=
,&
,#
这类字符是被允许的。
另一方面,对于 URL 的单个组件,例如一个搜索参数,则必须对这些字符进行编码,以免破坏 URL 的格式。
encodeURI
仅编码 URL 中完全禁止的字符。encodeURIComponent
也编码这类字符,此外,还编码#
,$
,&
,+
,,
,/
,:
,;
,=
,?
和@
字符。
所以,对于一个 URL 整体,我们可以使用 encodeURI
,
而对于 URL 参数,我们应该改用 encodeURIComponent
。
解析 URL 的 queryString
function parse(urlStr) {
const queryString = urlStr.match(/(?<=\?)[^\?#]*/)?.[0];
// const queryString = new URL(urlStr).search.slice(1);
if (!queryString) return {};
queryObj = queryString.split('&').reduce((params, block) => {
// const [k, v = ''] = decodeURIComponent(block).split('=');
// 如此操作无法正确识别 title=1%2B1%3D2 即 1+1=2
// 如果未赋值,则默认为空字符串
const [k, v = ''] = block.split('=').map(e => decodeURIComponent(e));
if (params[k] !== undefined) {
// 处理 key 出现多次的情况,设置为数组
params[k] = [].concat(params[k], v);
} else {
params[k] = v;
}
return params;
}, {})
return queryObj;
}
// {}
const str1 = 'https://shanyue.tech'
// {a: ''}
const str2 = 'https://shanyue.tech?a'
// {name: '名字'}
const str3 = 'https://shanyue.tech?name=%E5%90%8D%E5%AD%97'
// {name: '名字', a: 3}
const str4 = 'https://shanyue.tech?name=%E5%90%8D%E5%AD%97&a=3'
// {name: '名字', a: [3, 4]}
const str5 = 'https://shanyue.tech?name=%E5%90%8D%E5%AD%97&a=3&a=4'
// {name: '名字', a: 3}
const str6 = 'https://shanyue.tech?name=%E5%90%8D%E5%AD%97&a=3#hash'
// {name: '1+1=2'}
const str7 = 'https://shanyue.tech?name=1%2B1%3D2'
console.log('parse(str1): ', parse(str1));
console.log('parse(str2): ', parse(str2));
console.log('parse(str3): ', parse(str3));
console.log('parse(str4): ', parse(str4));
console.log('parse(str5): ', parse(str5));
console.log('parse(str6): ', parse(str6));
console.log('parse(str7): ', parse(str7));
编码 URL 的 queryString
function stringify(queryObj) {
const queryArr = [];
for (let [k, v] of Object.entries(queryObj)) {
if (v === null || v === undefined || typeof v === 'object') {
v = '';
}
queryArr.push(encodeURIComponent(k) + '=' + encodeURIComponent(v));
}
return queryArr.join('&');
}
const data = {
a: 123,
b: '啊?',
c: null
}
const queryString = stringify(data);
console.log('queryString: ', queryString);