3 回答

TA貢獻1860條經驗 獲得超8個贊
這似乎適用于您的簡單示例和更復雜的示例(現已更新以處理數字和布爾值):
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}
有兩個部分值得關注。
首先,這對逗號做了一個假設:它們表示數組元素之間的分隔。而且,更進一步,它假設空字符串不是有意的,從而將
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
進入這個:
watermark: [
? "https://s.ytimg.com/yts/img/watermark/youtube_watermark-vflHX6b6E.png",
? "https://s.ytimg.com/yts/img/watermark/youtube_hd_watermark-vflAzLcD6.png"
]
原始內容以編碼的逗號 ( %2C) 開頭,這會導致初始空字符串,因此我們使用.filter (Boolean)刪除它。
其次,對表示 JSON 的字符串的測試非常幼稚,僅執行.startsWith ('{'). 您可以將其替換為您需要的任何內容,但這會導致意圖問題。我不確定我們是否可以以這種方式完全通用地編寫此內容。
不過,我認為已經很接近了。而且代碼相當干凈。
然而,我確實想知道為什么。這么多數據將會遇到各種 url 大小限制。此時,將其放入請求正文而不是 url 參數不是更有意義嗎?

TA貢獻1765條經驗 獲得超5個贊
您可以通過檢查編碼符號來采用遞歸方法=。
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貢獻1802條經驗 獲得超6個贊
我使用Object.fromEntries?(new?URLSearchParams?())重新設計了算法。
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貢獻1865條經驗 獲得超7個贊
Node.js 附帶了一個內置的“querystring”npm 包實用程序,但在這里我使用了一個更好的實用程序,稱為“qs”。您可以在數組中指定分隔符,而不是僅對前者使用一個分隔符。
如果您想使用內置的“querystring”包,則需要在調用解析時刪除分隔符數組,并檢查字符串以查看使用的分隔符 - 您提供的示例文件使用了幾個不同的分隔符。
所以試試這個:
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));
添加回答
舉報