Эта статья возникла из-за частого требования анализа URL-адресов от руки в предыдущем интервью, поэтому я написал статью для этой ситуации, чтобы кратко описать, как анализировать URL-адрес. Если у вас есть лучший метод анализа или вариант типа вопроса, добро пожаловать на обсуждение
Обратите внимание, что в этой статье обсуждается только один из форматов, перечисленных в начале. Другие форматы для URL-адресов еще не обсуждались. Дополнительные форматы, соответствующие спецификации (например, использование относительных путей и т. д.), см.:tools.I ETF.org/HTML/RFC398…
как выглядит URL-адрес
Сначала давайте посмотрим, как выглядит полный URL:<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
Если это слишком абстрактно, давайте конкретизируем это на примере:https://juanni:miao@www.foo.com:8080/file;foo=1;bar=2?test=3&miao=4#test
компоненты | описывать | По умолчанию | |
---|---|---|---|
scheme | Протокол, используемый для доступа к серверу для получения ресурсов | без | https |
user | Имя пользователя для доступа к ресурсу | Нет (анонимно) | juanni |
password | Пароль пользователя и имя пользователя для использования: сегментация |
miao | |
host | Имя хоста сервера ресурсов или IP-адрес | без | www.foo.com |
port | Порт, который прослушивает сервер ресурсов. Разные схемы имеют разные порты по умолчанию (HTTP использует 80 в качестве порта по умолчанию). | связанный со схемой | 8080 |
path | Путь к ресурсу на сервере. Путь связан с сервером и схемой | По умолчанию | /file |
params | Укажите входные параметры для некоторых схем, которые представляют собой пары ключ-значение. Их может быть несколько, используйте; Разделение, несколько значений за одно использование, сегментация |
По умолчанию | foo=1;bar=2 |
query | Для этого компонента нет общего формата, и он в основном используется в HTTP.& для разделения нескольких запросов. использовать? отдельный запрос и другие части |
без | test=3&miao=4 |
frag/fragment | Небольшая часть или часть имени ресурса. При обращении к объекту фрагмент не будет отправлен на сервер, он используется внутри клиента. пройти через# отдельный фрагмент от остальных |
без | test |
из-заpath parameter
даpath
часть , поэтому мы классифицируем его какpath
середина
Между тем, если вы хотите указать, какие части являются необязательными, вы можете выразить это так:[scheme:]//[user[:password]@]host[:port][/path][?query][#fragment]
Как получить каждый компонент
Давайте не будем сначала рассматривать данные внутри компонента, а сначала получим каждый компонент
Пусть браузер поможет нам решить - URLUTILS
Сначала введите ленивый способ:URLUtils, через этот интерфейс можно получить href, имя хоста, порт и другие атрибуты.
В среде браузера нашa
ярлык, то естьHTMLAnchorElementДостигнутоURLUtils
свойства, определенные в , вы можете использовать следующий код для получения каждого компонента
/**
* @param {string} url
* 利用 URLUtils 简单解析 URL
* @returns {protocol, username, password, hostname, port, pathname, search, hash}
*/
function URLParser(url) {
const a = document.createElement('a');
a.href = url;
return {
protocol: a.protocol,
username: a.username,
password: a.password,
hostname: a.hostname, // host 可能包括 port, hostname 不包括
port: a.port,
pathname: a.pathname,
search: a.search,
hash: a.hash,
}
}
недостаток:
- Зависит от интерфейса среды хостинга браузера
использоватьURL
объект
использовать вышеa
Метод label не работает в среде Node, но у нас есть другие способы позволить базовому API проанализировать его для нас —URL
/**
* @param {string} url
* 利用 URLUtils 简单解析 URL
* @returns {protocol, username, password, hostname, port, pathname, search, hash}
*/
function URLParser(url) {
const urlObj = new URL(url);
return {
protocol: urlObj.protocol,
username: urlObj.username,
password: urlObj.password,
hostname: urlObj.hostname,
port: urlObj.port,
pathname: urlObj.pathname,
search: urlObj.search,
hash: urlObj.hash,
}
}
Честно шлепнуть по руке
Тогда если интервьюер захочет подрочить честно, то ему остается только подрочить на него:
function parseUrl(url) {
var pattern = RegExp("^(?:([^/?#]+))?//(?:([^:]*)(?::?(.*))@)?(?:([^/?#:]*):?([0-9]+)?)?([^?#]*)(\\?(?:[^#]*))?(#(?:.*))?");
var matches = url.match(pattern) || [];
return {
protocol: matches[1],
username: matches[2],
password: matches[3],
hostname: matches[4],
port: matches[5],
pathname: matches[6],
search: matches[7],
hash: matches[8]
};
}
parseUrl("https://juanni:miao@www.foo.com:8080/file;foo=1;bar=2?test=3&miao=4#test")
// hash: "#test"
// hostname: "www.foo.com"
// password: "miao"
// pathname: "/file;foo=1;bar=2"
// port: "8080"
// protocol: "https:"
// search: "?test=3&miao=4"
// username: "juanni"
Это правило действительно немного сложно понять, но я считаю, что если есть некоторые основы, его все же можно понять с помощью следующих двух картинок:
Разобрать часть поиска (запроса)
лень пользоватьсяURLSearchParams
/**
* @param {string} search 类似于 location.search
* @returns {object}
*/
function getUrlQueyr(search) {
const searchObj = {};
for (let [key, value] of new URLSearchParams(search)) {
searchObj[key] = value;
}
return searchObj;
}
преимущество:
- Нет необходимости использовать вручную
decodeURIComponent
- Поможет автоматически преобразовать + в запросе в пробел (используйте отдельно
decodeURIComponent
Не могу этого сделать) (что касается того, в каком случае пробелы преобразуются в+
, при каких обстоятельствах преобразовывать пробелы в%20
,МогуОбратитесь сюда и т.д.) - не поддерживается
array[]
/obj{}
Равная форма
Еще одна рука (неполная версия)
Требовать:
- Недопустимые символы не анализируются
- Для разбора в массив вида list[]
- Для анализируемых объектов в форме obj{} (пока вам нужно использовать только
JSON.parse
разбор)
/**
* @param {string} query 形如 location.search
* @returns {object}
*/
function parseQueryString(query) {
if (!query) {
return {};
}
query = query.replace(/^\?/, '');
const queryArr = query.split('&');
const result = {};
queryArr.forEach(query => {
let [key, value] = query.split('=');
try {
value = decodeURIComponent(value || '').replace(/\+/g, ' ');
key = decodeURIComponent(key || '').replace(/\+/g, ' ');
} catch (e) {
// 非法
console.log(e);
return;
}
const type = getQuertType(key);
switch(type) {
case 'ARRAY':
key = key.replace(/\[\]$/, '')
if (!result[key]) {
result[key] = [value];
} else {
result[key].push(value);
}
break;
case 'JSON':
key = key.replace(/\{\}$/, '')
value = JSON.parse(value);
result.json = value;
break;
default:
result[key] = value;
}
});
return result;
function getQuertType (key) {
if (key.endsWith('[]')) return 'ARRAY';
if (key.endsWith('{}')) return 'JSON';
return 'DEFAULT';
}
}
const testUrl =
'?name=coder&age=20&callback=https%3A%2F%2Fmiaolegemi.com%3Fname%3Dtest&list[]=a&list[]=b&json{}=%7B%22str%22%3A%22abc%22,%22num%22%3A123%7D&illegal=C%9E5%H__a100373__b4'
parseQueryString(testUrl)
Конечно, это не строго, и не рассматривались следующие вопросы.
- Как работать с одним и тем же полем
- нет замены
+
для - Только
key
- Только
value
- Относительные пути не разрешаются
- более глубокий анализ
Object
Наконец, здесь рекомендуется библиотека с открытым исходным кодом:url-parse, лучше справляется с различными ситуациями, и это также означает, что реализация немного сложна, просто поймите это.На собеседовании необходимо полностью понять требования интервьюера, чтобы ответить и расширить