Как мне разобрать URL в имя хоста и путь в JavaScript?


380

Я хотел бы взять строку

var a = "http://example.com/aa/bb/"

и обработать его в объект, так что

a.hostname == "example.com"

а также

a.pathname == "/aa/bb"

11
Если вы работаете с текущим URL, вы можете получить доступ hostnameи pathnameнепосредственно к locationобъекту.
rvighne

1
что насчет "lastPathPart"?
Виктор

Не регулярное выражение, а модуль Python tldextract делает это точно: github.com/john-kurkowski/tldextract
Оливер Оливер

Ответы:


400

Современный способ:

new URL("http://example.com/aa/bb/")

Возвращает объект со свойствами hostnameи pathname, вместе с несколькими другими .

Первый аргумент - это относительный или абсолютный URL; если он относительный, то вам нужно указать второй аргумент (базовый URL). Например, для URL относительно текущей страницы:

new URL("/aa/bb/", location)

В дополнение к браузерам этот API также доступен в Node.js начиная с v7, через require('url').URL.


7
Ницца! Относительные URL ломают это хотя ... :( new URL('/stuff?foo=bar#baz')->SyntaxError: Failed to construct 'URL': Invalid URL
lakenen

56
Экспериментальная технология: IE не поддерживает это! developer.mozilla.org/en-US/docs/Web/API/URL/…
cvouter

10
@cwouter: Тем не менее, он работает в Edge, который заменяет IE
rvighne

4
это способ сделать это, край уже 3 версии на вершине, то есть, так что это не имеет значения
Клаудиу Крянгэ

7
Тот факт, что в JavaScript нет встроенного способа анализа URL-адресов, который работает в браузерах или на серверах, довольно печален ...
Skitterm

365
var getLocation = function(href) {
    var l = document.createElement("a");
    l.href = href;
    return l;
};
var l = getLocation("http://example.com/path");
console.debug(l.hostname)
>> "example.com"
console.debug(l.pathname)
>> "/path"

14
Вы уверены, что это кросс-браузерное совместимое решение?
cllpse

70
Следует отметить, что, хотя это может помочь / ответить на оригинальный постер, этот ответ будет работать только для людей, выполняющих работу JS в браузере, поскольку он полагается на работу DOM.
Адам Баткин

4
Еще один пример простоты, наряду с изобретательностью.
Саид Нимати

26
Не работает в IE, если href относительно. l.hostname будет пустым. Если вы предоставляете только полные URL-адреса, это будет работать.
Дерек Приор

7
Даже с абсолютными URL-адресами IE (протестированный в IE 11) ведет себя не так, как Chrome и Firefox. IE pathnameудаляет косую черту, в то время как другие браузеры этого не делают. Таким образом, вы будете в конечном итоге с /pathили path, в зависимости от вашего браузера.
TrueWill

299

найти здесь: https://gist.github.com/jlong/2428561

var parser = document.createElement('a');
parser.href = "http://example.com:3000/pathname/?search=test#hash";

parser.protocol; // => "http:"
parser.host;     // => "example.com:3000"
parser.hostname; // => "example.com"
parser.port;     // => "3000"
parser.pathname; // => "/pathname/"
parser.hash;     // => "#hash"
parser.search;   // => "?search=test"
parser.origin;   // => "http://example.com:3000"

11
Обратите внимание, что если вы просто хотите получить проанализированные части текущего местоположения браузера, первые две строки становятся parser = location;и все следующие строки работают. Пробовал в Chrome и IE9 только сейчас.
Ли Меадор

9
Также обратите внимание, что pathnameв IE отсутствует косая черта. Пойди разберись. : D
Невелис

3
Для IE используйте "/" + parser.pathname
sbose

Предупреждение: он вернется, http:даже если вы перейдете просто domain.comк href (без какого-либо протокола). Я хотел использовать это, чтобы проверить, отсутствует ли протокол, и если да, то я мог бы добавить его, но он предполагает http: поэтому не смог использовать его для этой цели.
Макс Ходжес

Имя хоста фактически включает протокол. Тест на последнюю версию Chrome.
AndroidDev

109

Вот простая функция, использующая регулярное выражение, имитирующее aповедение тега.

Pros

  • предсказуемое поведение (нет проблем с несколькими браузерами)
  • не нуждается в DOM
  • это действительно коротко.

Cons

  • Регулярное выражение немного трудно читать

-

function getLocation(href) {
    var match = href.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/);
    return match && {
        href: href,
        protocol: match[1],
        host: match[2],
        hostname: match[3],
        port: match[4],
        pathname: match[5],
        search: match[6],
        hash: match[7]
    }
}

-

getLocation("http://example.com/");
/*
{
    "protocol": "http:",
    "host": "example.com",
    "hostname": "example.com",
    "port": undefined,
    "pathname": "/"
    "search": "",
    "hash": "",
}
*/

getLocation("http://example.com:3000/pathname/?search=test#hash");
/*
{
    "protocol": "http:",
    "host": "example.com:3000",
    "hostname": "example.com",
    "port": "3000",
    "pathname": "/pathname/",
    "search": "?search=test",
    "hash": "#hash"
}
*/

РЕДАКТИРОВАТЬ:

Вот разбивка регулярного выражения

var reURLInformation = new RegExp([
    '^(https?:)//', // protocol
    '(([^:/?#]*)(?::([0-9]+))?)', // host (hostname and port)
    '(/{0,1}[^?#]*)', // pathname
    '(\\?[^#]*|)', // search
    '(#.*|)$' // hash
].join(''));
var match = href.match(reURLInformation);

4
Не работает с какими-либо относительными URL. Следовали ли вы RFC-3986 при создании регулярного выражения? > getLocation ("// example.com/"); null> getLocation ("/ pathname /? search"); null> getLocation ("/ pathname /"); null> getLocation ("относительный"); null
gregers

2
Мне нравится, как это не использует DOM, но Грегерс имеет хорошую точку. Было бы хорошо, если бы он мог обрабатывать относительные пути. Для заполнения пробелов и добавления кода потребуется использовать window.location (элемент a). В этом случае метод стал бы лицемерным. Если нет альтернативы, не уверен, как это можно решить идеально.
Turbo

Добавлен ключ href с оригинальным URL, что обеспечивает согласованность этого возвращаемого объекта с реализацией dom.
mattdlockyer

2
Если кому-то нужно проанализировать относительные URL-адреса, обновленное регулярное выражение: / ^ (? :( https? \:) \ / \ /)? (([^: \ /? #] *) (?: \: ([0 -9] +))?) ([\ /] {0,1} [^? #] *) (\? [^ #] * |) (#. * |) $ /
шленский

75
var loc = window.location;  // => "http://example.com:3000/pathname/?search=test#hash"

возвращает currentUrl.

Если вы хотите передать свою собственную строку как URL ( не работает в IE11 ):

var loc = new URL("http://example.com:3000/pathname/?search=test#hash")

Тогда вы можете разобрать это как:

loc.protocol; // => "http:"
loc.host;     // => "example.com:3000"
loc.hostname; // => "example.com"
loc.port;     // => "3000"
loc.pathname; // => "/pathname/"
loc.hash;     // => "#hash"
loc.search;   // => "?search=test"

60

Ответ freddiefujiwara довольно хороший, но мне также нужно было поддерживать относительные URL в Internet Explorer. Я придумал следующее решение:

function getLocation(href) {
    var location = document.createElement("a");
    location.href = href;
    // IE doesn't populate all link properties when setting .href with a relative URL,
    // however .href will return an absolute URL which then can be used on itself
    // to populate these additional fields.
    if (location.host == "") {
      location.href = location.href;
    }
    return location;
};

Теперь используйте его, чтобы получить необходимые свойства:

var a = getLocation('http://example.com/aa/bb/');
document.write(a.hostname);
document.write(a.pathname);

Пример JSFiddle: http://jsfiddle.net/6AEAB/


4
Это должен быть принятый ответ. Очень умное использование относительной к абсолютной обработке URL. +1
L0j1k

По-видимому, не в первый раз, когда умерла ссылка JSFiddle: stackoverflow.com/questions/25179964/…
Клаус

3
Это работало отлично, однако у меня было одно обновление, которое, я надеюсь, поможет другим. Я использую это для проверки источника в запросе postMessage, и когда порт является портом по умолчанию (80 или 443), он не добавляется к пути. Я условно проверил это при создании своего URL: var locationHost = (location.port !== '80' && location.port !== '443') ? location.host : location.hostname; var locationOrigin = location.protocol + '//' + locationHost;
rhoster

2
Я сделал этот комментарий в другом месте о более популярном варианте этого решения, но так как это было мое любимое решение, я хотел повторить это здесь. В IE11 наличие имени пользователя в href приведет к тому, что все эти чтения свойств приведут к ошибкам безопасности. Пример: " example.com " будет работать нормально. Но « username@www.example.com » или « username: password@www.example.com » будет пытаться ссылаться на одно из других свойств элемента привязки (например, hash), чтобы завершиться с ошибкой и выдать неприятную ошибку.
Clippy

17

js-uri (доступно в Google Code) берет строковый URL-адрес и разрешает из него объект URI:

var some_uri = new URI("http://www.example.com/foo/bar");

alert(some_uri.authority); // www.example.com
alert(some_uri);           // http://www.example.com/foo/bar

var blah      = new URI("blah");
var blah_full = blah.resolve(some_uri);
alert(blah_full);         // http://www.example.com/foo/blah

Спасибо!!! но я хочу указать uri = новое местоположение (" example.com/aa/bb" ) typeof (window.location) == typeof (uri)
freddiefujiwara

Поскольку window.location - это строка, я не вижу, насколько это возможно или полезно. Почему типы должны совпадать, когда вы можете легко конвертировать из одного в другой?
Рекс М

developer.mozilla.org/en/DOM/window.location очень хороший API! поэтому я надеюсь преобразовать String в объект window.location
freddiefujiwara

1
Настройка window.location меняет браузер, поэтому этого не произойдет.
epascarello

1
Хм это правильно. window.location не является строкой, но может быть назначен из строки. Я не уверен, что это можно имитировать, я пытался назначить прототип местоположения для нового объекта URI, но это не сработало.
Рекс М

12

Как насчет простого регулярного выражения?

url = "http://www.example.com/path/to/somwhere";
urlParts = /^(?:\w+\:\/\/)?([^\/]+)(.*)$/.exec(url);
hostname = urlParts[1]; // www.example.com
path = urlParts[2]; // /path/to/somwhere

Попробуйте проанализировать что-то действительное, например, //user:password@example.com/path/x?y=zи вы поймете, почему простое регулярное выражение не обрезает это. Теперь добавьте к нему что-то недопустимое, и оно также должно выручить предсказуемым образом.
Микко Ранталайнен

Простое регулярное выражение предназначено для простых задач :) Но мне не кажется, что URL, как это, не может быть проанализировано регулярным выражением, ему просто потребуется еще несколько настроек. Но я бы, наверное, пошел за какой-нибудь библиотекой, если мне нужно что-то более сложное и пуленепробиваемое.
Свестка

12

Сегодня я столкнулся с этой проблемой и обнаружил: URL - MDN Web API

var url = new URL("http://test.example.com/dir/subdir/file.html#hash");

Это возвращение:

{ hash:"#hash", host:"test.example.com", hostname:"test.example.com", href:"http://test.example.com/dir/subdir/file.html#hash", origin:"http://test.example.com", password:"", pathname:"/dir/subdir/file.html", port:"", protocol:"http:", search: "", username: "" }

Надеюсь, мой первый вклад поможет вам!


Двойной ответ
Мартин ван Дриэль

6
Да, но парень наверху просто обновляет свой awser в 2017 году, я выкладываю его в 2016 году.
A. Moynet

Ах, мой плохой, извините
Мартин ван Дриэль

9

Вот версия, которую я скопировал с https://gist.github.com/1847816 , но переписал, чтобы ее было легче читать и отлаживать. Цель копирования данных привязки в другую переменную с именем «result» состоит в том, что данные привязки являются довольно длинными, и поэтому копирование ограниченного числа значений в результат поможет упростить результат.

/**
 * See: https://gist.github.com/1847816
 * Parse a URI, returning an object similar to Location
 * Usage: var uri = parseUri("hello?search#hash")
 */
function parseUri(url) {

  var result = {};

  var anchor = document.createElement('a');
  anchor.href = url;

  var keys = 'protocol hostname host pathname port search hash href'.split(' ');
  for (var keyIndex in keys) {
    var currentKey = keys[keyIndex]; 
    result[currentKey] = anchor[currentKey];
  }

  result.toString = function() { return anchor.href; };
  result.requestUri = result.pathname + result.search;  
  return result;

}

6

Кросс-браузерный разбор URL , обходит проблему относительного пути для IE 6, 7, 8 и 9:

function ParsedUrl(url) {
    var parser = document.createElement("a");
    parser.href = url;

    // IE 8 and 9 dont load the attributes "protocol" and "host" in case the source URL
    // is just a pathname, that is, "/example" and not "http://domain.com/example".
    parser.href = parser.href;

    // IE 7 and 6 wont load "protocol" and "host" even with the above workaround,
    // so we take the protocol/host from window.location and place them manually
    if (parser.host === "") {
        var newProtocolAndHost = window.location.protocol + "//" + window.location.host;
        if (url.charAt(1) === "/") {
            parser.href = newProtocolAndHost + url;
        } else {
            // the regex gets everything up to the last "/"
            // /path/takesEverythingUpToAndIncludingTheLastForwardSlash/thisIsIgnored
            // "/" is inserted before because IE takes it of from pathname
            var currentFolder = ("/"+parser.pathname).match(/.*\//)[0];
            parser.href = newProtocolAndHost + currentFolder + url;
        }
    }

    // copies all the properties to this object
    var properties = ['host', 'hostname', 'hash', 'href', 'port', 'protocol', 'search'];
    for (var i = 0, n = properties.length; i < n; i++) {
      this[properties[i]] = parser[properties[i]];
    }

    // pathname is special because IE takes the "/" of the starting of pathname
    this.pathname = (parser.pathname.charAt(0) !== "/" ? "/" : "") + parser.pathname;
}

Использование ( демо JSFiddle здесь ):

var myUrl = new ParsedUrl("http://www.example.com:8080/path?query=123#fragment");

Результат:

{
    hash: "#fragment"
    host: "www.example.com:8080"
    hostname: "www.example.com"
    href: "http://www.example.com:8080/path?query=123#fragment"
    pathname: "/path"
    port: "8080"
    protocol: "http:"
    search: "?query=123"
}

5

Для тех, кто ищет современное решение, которое работает в IE, Firefox и Chrome:

Ни одно из этих решений, использующих элемент гиперссылки, не будет работать так же в Chrome.Если вы передадите неверный (или пустой) URL-адрес chrome, он всегда будет возвращать хост, с которого вызывается скрипт. Таким образом, в IE вы получите пустой, в то время как в Chrome вы получите localhost (или любой другой).

Если вы пытаетесь посмотреть на реферера, это обман. Вы хотите убедиться, что хост, который вы получаете, был в исходном URL, чтобы справиться с этим:

    function getHostNameFromUrl(url) {
        // <summary>Parses the domain/host from a given url.</summary>
        var a = document.createElement("a");
        a.href = url;

        // Handle chrome which will default to domain where script is called from if invalid
        return url.indexOf(a.hostname) != -1 ? a.hostname : '';
    }

Это очень важная вещь для рассмотрения!
2rs2ts

Это полностью нарушает относительные URL, хотя!
Лакенен

4

Путь AngularJS - возитесь здесь: http://jsfiddle.net/PT5BG/4/

<!DOCTYPE html>
<html>
<head>
    <title>Parse URL using AngularJS</title>
</head>
<body ng-app ng-controller="AppCtrl" ng-init="init()">

<h3>Parse URL using AngularJS</h3>

url: <input type="text" ng-model="url" value="" style="width:780px;">

<ul>
    <li>href = {{parser.href}}</li>
    <li>protocol = {{parser.protocol}}</li>
    <li>host = {{parser.host}}</li>
    <li>hostname = {{parser.hostname}}</li>
    <li>port = {{parser.port}}</li>
    <li>pathname = {{parser.pathname}}</li>
    <li>hash = {{parser.hash}}</li>
    <li>search = {{parser.search}}</li>
</ul>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>

<script>
function AppCtrl($scope) {

    $scope.$watch('url', function() {
        $scope.parser.href = $scope.url;
    });

    $scope.init = function() {
        $scope.parser = document.createElement('a');
        $scope.url = window.location;
    }

}
</script>

</body>
</html>

2
Это будет более угловатым, если вы будете использовать $documentи $windowуслуги
Чернов

3

Простое и надежное решение с использованием шаблона модуля. Это включает исправление для IE, где pathnameне всегда есть начальная косая черта ( /).

Я создал Gist вместе с JSFiddle, который предлагает более динамический анализатор. Я рекомендую вам проверить это и оставить отзыв.

var URLParser = (function (document) {
    var PROPS = 'protocol hostname host pathname port search hash href'.split(' ');
    var self = function (url) {
        this.aEl = document.createElement('a');
        this.parse(url);
    };
    self.prototype.parse = function (url) {
        this.aEl.href = url;
        if (this.aEl.host == "") {
           this.aEl.href = this.aEl.href;
        }
        PROPS.forEach(function (prop) {
            switch (prop) {
                case 'hash':
                    this[prop] = this.aEl[prop].substr(1);
                    break;
                default:
                    this[prop] = this.aEl[prop];
            }
        }, this);
        if (this.pathname.indexOf('/') !== 0) {
            this.pathname = '/' + this.pathname;
        }
        this.requestUri = this.pathname + this.search;
    };
    self.prototype.toObj = function () {
        var obj = {};
        PROPS.forEach(function (prop) {
            obj[prop] = this[prop];
        }, this);
        obj.requestUri = this.requestUri;
        return obj;
    };
    self.prototype.toString = function () {
        return this.href;
    };
    return self;
})(document);

демонстрация

Вывод

{
 "protocol": "https:",
 "hostname": "www.example.org",
 "host": "www.example.org:5887",
 "pathname": "/foo/bar",
 "port": "5887",
 "search": "?a=1&b=2",
 "hash": "section-1",
 "href": "https://www.example.org:5887/foo/bar?a=1&b=2#section-1",
 "requestUri": "/foo/bar?a=1&b=2"
}
{
 "protocol": "ftp:",
 "hostname": "www.files.com",
 "host": "www.files.com:22",
 "pathname": "/folder",
 "port": "22",
 "search": "?id=7",
 "hash": "",
 "href": "ftp://www.files.com:22/folder?id=7",
 "requestUri": "/folder?id=7"
}


3

Почему бы не использовать его?

        $scope.get_location=function(url_str){
        var parser = document.createElement('a');
        parser.href =url_str;//"http://example.com:3000/pathname/?search=test#hash";
        var info={
            protocol:parser.protocol,   
            hostname:parser.hostname, // => "example.com"
            port:parser.port,     // => "3000"
            pathname:parser.pathname, // => "/pathname/"
            search:parser.search,   // => "?search=test"
            hash:parser.hash,     // => "#hash"
            host:parser.host, // => "example.com:3000"      
        }
        return info;
    }
    alert( JSON.stringify( $scope.get_location("http://localhost:257/index.php/deploy/?asd=asd#asd"),null,4 ) );

3

Вы также можете использовать parse_url()функцию из Locutus проекта (бывший php.js).

Код:

parse_url('http://username:password@hostname/path?arg=value#anchor');

Результат:

{
  scheme: 'http',
  host: 'hostname',
  user: 'username',
  pass: 'password',
  path: '/path',
  query: 'arg=value',
  fragment: 'anchor'
}

1
этот URL не работает для меня, но я нашел его здесь github.com/hirak/phpjs/blob/master/functions/url/parse_url.js
Стэн Куинн

@StanQuinn, потому что php.js изменил свое имя на Locutus. Я обновил свой ответ новой ссылкой.
Андрей Руденко

3
function parseUrl(url) {
    var m = url.match(/^(([^:\/?#]+:)?(?:\/\/((?:([^\/?#:]*):([^\/?#:]*)@)?([^\/?#:]*)(?::([^\/?#:]*))?)))?([^?#]*)(\?[^#]*)?(#.*)?$/),
        r = {
            hash: m[10] || "",                   // #asd
            host: m[3] || "",                    // localhost:257
            hostname: m[6] || "",                // localhost
            href: m[0] || "",                    // http://username:password@localhost:257/deploy/?asd=asd#asd
            origin: m[1] || "",                  // http://username:password@localhost:257
            pathname: m[8] || (m[1] ? "/" : ""), // /deploy/
            port: m[7] || "",                    // 257
            protocol: m[2] || "",                // http:
            search: m[9] || "",                  // ?asd=asd
            username: m[4] || "",                // username
            password: m[5] || ""                 // password
        };
    if (r.protocol.length == 2) {
        r.protocol = "file:///" + r.protocol.toUpperCase();
        r.origin = r.protocol + "//" + r.host;
    }
    r.href = r.origin + r.pathname + r.search + r.hash;
    return m && r;
};
parseUrl("http://username:password@localhost:257/deploy/?asd=asd#asd");

Работает как с абсолютными, так и с относительными URL


abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
树 at 和 葡萄 树

@ 山 茶树 和 葡萄 树 Я обновил код, чтобы правильно обрабатывать подкомпонент userinfo. Спасибо за ваш комментарий, я не замечал этой проблемы раньше
Николай

люблю это регулярное выражение
Кунал

2

Прекратите изобретать велосипед. Используйте https://github.com/medialize/URI.js/

var uri = new URI("http://example.org:80/foo/hello.html");
// get host
uri.host(); // returns string "example.org:80"
// set host
uri.host("example.org:80");

5
Потому что каждый раз, когда вы хотите решить проблему ... использовать библиотеку? Хорошо ... (не)
jiminikiz

4
Не всегда (на самом деле почти никогда), но URL очень сложно разобрать, в RFC много деталей. Лучше использовать библиотеку, которая была использована и проверена тысячами.
Уго Секейра

Как насчет того, чтобы просто использовать то, что встроено, вместо того, чтобы кто-то другой изобрел колесо с библиотекой? Смотрите stackoverflow.com/a/24006120/747739
Фил

IE11 не поддерживает встроенную функцию, поэтому эта библиотека отлично работает. Сказать, что никогда не использовать библиотеку - это все равно что сказать, что мы никогда не должны были использовать jQuery и просто писать нативный код, что абсолютно нелепо. У каждого разработчика свой вариант использования, нет «лучшего» способа, иногда ванильный / нативный работает лучше, а иногда нет… что 92% разработчиков все еще должны учиться.
tno2007


1

простой взлом с первым ответом

var getLocation = function(href=window.location.href) {
    var l = document.createElement("a");
    l.href = href;
    return l;
};

это может использоваться даже без аргумента, чтобы выяснить текущее имя хоста getLocation (). имя хоста даст текущее имя хоста

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.