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

380

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

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

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

a.hostname == "example.com"

а также

a.pathname == "/aa/bb"
freddiefujiwara
источник
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.

rvighne
источник
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"
freddiefujiwara
источник
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);
Rems
источник
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
Švestka
источник
Попробуйте проанализировать что-то действительное, например, //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"
}
acdcjunior
источник
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 : '';
    }
KingOfHypocrites
источник
Это очень важная вещь для рассмотрения!
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 ) );
tanthuc
источник
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

Просто используйте библиотеку url.js (для web и node.js).

https://github.com/websanova/js-url

url: http://example.com?param=test#param=again

url('?param'); // test
url('#param'); // again
url('protocol'); // http
url('port'); // 80
url('domain'); // example.com
url('tld'); // com

etc...
обкрадывать
источник
1

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

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

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

sooraj
источник