Распространенные вопросы на собеседовании — анализ URL-адресов

внешний интерфейс сервер регулярное выражение опрос

Эта статья возникла из-за частого требования анализа 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 Пароль пользователя и имя пользователя для использования:сегментация E-mail 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"

Это правило действительно немного сложно понять, но я считаю, что если есть некоторые основы, его все же можно понять с помощью следующих двух картинок:

image.png | left | 747x138

image.png | left | 747x70

Разобрать часть поиска (запроса)

лень пользоваться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)

Конечно, это не строго, и не рассматривались следующие вопросы.

  1. Как работать с одним и тем же полем
  2. нет замены+для
  3. Толькоkey
  4. Толькоvalue
  5. Относительные пути не разрешаются
  6. более глубокий анализObject

Наконец, здесь рекомендуется библиотека с открытым исходным кодом:url-parse, лучше справляется с различными ситуациями, и это также означает, что реализация немного сложна, просто поймите это.На собеседовании необходимо полностью понять требования интервьюера, чтобы ответить и расширить

Ссылаться на