3 回答

TA貢獻(xiàn)1860條經(jīng)驗(yàn) 獲得超8個(gè)贊
這似乎適用于您的簡(jiǎn)單示例和更復(fù)雜的示例(現(xiàn)已更新以處理數(shù)字和布爾值):
const parse = (query) =>
? query .startsWith ('{')
? ? ? JSON .parse (query)
? : query .includes ('&') || query .includes ('=')
? ? ? Object .fromEntries (
? ? ? ? query .split ('&')?
? ? ? ? ? .map (p => p .split ('='))
? ? ? ? ? .map (([k, v]) => [k, parse (decodeURIComponent (v))])
? ? ? )
? : query .includes (',')
? ? ? query .split (',') .filter (Boolean) .map (parse)
? : isFinite (query)
? ? ? Number (query)
? : query .toLowerCase () == "true" || query .toLowerCase () == "false"
? ? ? query .toLowerCase () == "true"
? : // else
? ? query
const q = 'foo=bar&foo1=foo%3Dbar%26foo2%3Dfoo%253Dbar'
console .log (parse(q))
console.log('fetching larger example...')
fetch ('https://gist.githubusercontent.com/avi12/cd1d6728445608d64475809a8ddccc9c/raw/030974baed3eaadb26d9378979b83b1d30a265a3/url-input-example.txt')
? .then (res => res .text ())
? .then (parse)
? .then (console .log)
.as-console-wrapper {max-height: 100% !important; top: 0}
有兩個(gè)部分值得關(guān)注。
首先,這對(duì)逗號(hào)做了一個(gè)假設(shè):它們表示數(shù)組元素之間的分隔。而且,更進(jìn)一步,它假設(shè)空字符串不是有意的,從而將
watermark=%2Chttps%3A%2F%2Fs.ytimg.com%2Fyts%2Fimg%2Fwatermark%2Fyoutube_watermark-vflHX6b6E.png
%2Chttps%3A%2F%2Fs.ytimg.com%2Fyts%2Fimg%2Fwatermark%2Fyoutube_hd_watermark-vflAzLcD6.png
進(jìn)入這個(gè):
watermark: [
? "https://s.ytimg.com/yts/img/watermark/youtube_watermark-vflHX6b6E.png",
? "https://s.ytimg.com/yts/img/watermark/youtube_hd_watermark-vflAzLcD6.png"
]
原始內(nèi)容以編碼的逗號(hào) ( %2C) 開(kāi)頭,這會(huì)導(dǎo)致初始空字符串,因此我們使用.filter (Boolean)刪除它。
其次,對(duì)表示 JSON 的字符串的測(cè)試非常幼稚,僅執(zhí)行.startsWith ('{'). 您可以將其替換為您需要的任何內(nèi)容,但這會(huì)導(dǎo)致意圖問(wèn)題。我不確定我們是否可以以這種方式完全通用地編寫(xiě)此內(nèi)容。
不過(guò),我認(rèn)為已經(jīng)很接近了。而且代碼相當(dāng)干凈。
然而,我確實(shí)想知道為什么。這么多數(shù)據(jù)將會(huì)遇到各種 url 大小限制。此時(shí),將其放入請(qǐng)求正文而不是 url 參數(shù)不是更有意義嗎?

TA貢獻(xiàn)1765條經(jīng)驗(yàn) 獲得超5個(gè)贊
您可以通過(guò)檢查編碼符號(hào)來(lái)采用遞歸方法=。
const getValues = string => string.split('&')
.reduce((r, pair) => {
let [key, value] = pair.split('=');
value = decodeURIComponent(value);
r[key] = value.includes('=')
? getValues(value)
: value;
return r;
}, {});
console.log(getValues('foo=bar&foo1=foo%3Dbar%26foo2%3Dfoo%253Dbar'));

TA貢獻(xiàn)1802條經(jīng)驗(yàn) 獲得超6個(gè)贊
我使用Object.fromEntries?(new?URLSearchParams?())重新設(shè)計(jì)了算法。
function parse(query) {
? try {
? ? return JSON.parse(query);
? } catch {
? ? if (!isNaN(query)) {
? ? ? return Number(query);
? ? }
? ? if (typeof query !== "string") {
? ? ? const obj = {};
? ? ? for (const queryKey in query) {
? ? ? ? if (query.hasOwnProperty(queryKey)) {
? ? ? ? ? obj[queryKey] = parse(query[queryKey]);
? ? ? ? }
? ? ? }
? ? ? return obj;
? ? }
? ? if (!query) {
? ? ? return "";
? ? }
? ? if (query.toLowerCase().match(/^(true|false)$/)) {
? ? ? return query.toLowerCase() === "true";
? ? }
? ? const object = Object.fromEntries(new URLSearchParams(query));
? ? const values = Object.values(object);
? ? if (values.length === 1 && values[0] === "") {
? ? ? return query;
? ? }
? ? return parse(object);
? }
}
const q = 'foo=bar&foo1=foo%3Dbar%26foo2%3Dfoo%253Dbar';
console.log(parse(q));
console.log('fetching larger example...');
fetch('https://gist.githubusercontent.com/avi12/cd1d6728445608d64475809a8ddccc9c/raw/030974baed3eaadb26d9378979b83b1d30a265a3/url-input-example.txt')
? .then(response => response.text())
? .then(parse)
? .then(console.log);
.as-console-wrapper { max-height: 100% !important; top: 0; }

TA貢獻(xiàn)1865條經(jīng)驗(yàn) 獲得超7個(gè)贊
Node.js 附帶了一個(gè)內(nèi)置的“querystring”npm 包實(shí)用程序,但在這里我使用了一個(gè)更好的實(shí)用程序,稱(chēng)為“qs”。您可以在數(shù)組中指定分隔符,而不是僅對(duì)前者使用一個(gè)分隔符。
如果您想使用內(nèi)置的“querystring”包,則需要在調(diào)用解析時(shí)刪除分隔符數(shù)組,并檢查字符串以查看使用的分隔符 - 您提供的示例文件使用了幾個(gè)不同的分隔符。
所以試試這個(gè):
const qs = require("qs");
let params = `foo=bar&foo1=foo%3Dbar%26foo2%3Dfoo%253Dbar`;
const isObject = (param) => {
try {
let testProp = JSON.parse(param);
if (typeof testProp === "object" && testProp !== null) {
return true;
}
return false;
} catch (e) {
return false;
}
};
const isURL = (value) => {
try {
new URL(value);
} catch (e) {
return false;
}
return true;
};
const isQueryString = (value) => {
if (/[/&=]/.test(value) && !isURL(value)) {
return true;
} else {
return false;
}
};
const parseData = (data, parsed = false) => {
if (isQueryString(data) && !parsed) {
return parseData(qs.parse(data, { delimiter: /[;,/&]/ }), true);
} else if (isObject(data) || parsed) {
for (let propertyName in data) {
if (isObject(data[propertyName])) {
data[propertyName] = parseData(JSON.parse(data[propertyName]), true);
} else {
data[propertyName] = parseData(data[propertyName]);
}
}
return data;
} else {
return data;
}
};
let s = parseData(params);
console.log(JSON.stringify(s, null, 2));
添加回答
舉報(bào)