如何将URL解析为javascript中的主机名和路径?


379

我想带一个弦

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

并将其处理为一个对象

a.hostname == "example.com"

a.pathname == "/aa/bb"

11
如果你在当前的URL时,您可以访问hostnamepathname从直接location对象。
rvighne 2014年

1
那“ lastPathPart”呢?
维克多

不是正则表达式,而是Python模块tldextract完全做到了这一点:github.com/john-kurkowski/tldextract
Oliver Oliver

Answers:


395

现代方式:

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

返回与属性的对象hostnamepathname,连同其他几个人

第一个参数是相对网址或绝对网址;如果是相对的,则需要指定第二个参数(基本URL)。例如,对于相对于当前页面的URL:

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

除了浏览器之外,从v7开始,该API还可以在Node.js中使用require('url').URL


7
真好!相对网址虽然可以解决问题... :( new URL('/stuff?foo=bar#baz')->SyntaxError: Failed to construct 'URL': Invalid URL
lakenen 2014年

56
实验技术:IE不支持此功能!developer.mozilla.org/en-US/docs/Web/API/URL/...
cwouter

10
@cwouter:但是它确实在Edge中工作,它取代了IE
rvighne

4
这是做到这一点的方式,edge在ie之上已经有3个版本,所以没关系
Claudiu Creanga 16'Aug

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来完成其工作。
2009年

4
简洁性与巧思的另一个例子。
Saeed Neamati

26
如果href是相对的,则在IE中不起作用。l.hostname将为空。如果您仅提供完整的URL,则可以使用。
Derek 2012年

7
即使使用绝对URL,IE(在IE 11中测试)的行为也不同于Chrome和Firefox。IE pathname消除了斜杠,而其他浏览器则没有。因此,最终将使用/pathpath,具体取决于您的浏览器。
TrueWill 2015年

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
请注意,如果只想获取当前浏览器位置的已解析部分,则第1行变为第2行parser = location;,随后的所有行均有效。刚刚在Chrome和IE9中进行了尝试。
Lee Meador

9
另请注意,pathname它不包含IE中的前导斜线。去搞清楚。:D
nevelis

3
对于IE,请使用“ /” + parser.pathname
sbose 2014年

警告:http:即使您仅传递domain.com给href(没有任何协议),它也会返回。我想用它来检查协议是否丢失,如果可以,我可以添加它,但是它假定使用http:,因此无法用于此目的。
Max Hodges 2014年

主机名实际上包括协议。在最新版本的Chrome上进行测试。
AndroidDev

109

这是一个使用正则表达式的简单函数,它模仿了a标记行为。

优点

  • 可预测的行为(没有跨浏览器问题)
  • 不需要DOM
  • 真的很短

缺点

  • regexp有点难读

--

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(“ relative”); null
gregers 2014年

2
我喜欢它不使用DOM的方式,但是gregers有一个很好的观点。如果这可以处理相对路径,那就太好了。它将需要使用window.location(一个元素)来填补空白并添加代码。在这种情况下,该方法将变得虚伪。除非有其他选择,否则不确定如何完美解决。
2014年

使用原始URL添加了href键,这与dom实现的返回对象保持一致。
mattdlockyer

2
如果有人需要解析相对URL,则这里是更新的正则表达式:/ ^(?:( https?\:)\ / \ /)?(([[^:\ /?#] *)(?:\:([0 -9] +)))?)()([\ /] {0,1} [^?#] *)(\?[^#] * |)(#。* |)$ /
shlensky

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的答案很好,但我还需要在Internet Explorer中支持相对URL。我想出了以下解决方案:

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 2016年

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 = new Location(“ example.com/aa/bb”)typeof(window.location)== typeof(uri)
freddiefujiwara

由于window.location是一个字符串,所以我真的看不出来这怎么可能或有帮助。当您可以轻松地从一种转换为另一种类型时,为什么需要匹配这些类型?
Rex M

developer.mozilla.org/en/DOM/window.location是非常好的api !!所以我希望将String转换为window.location对象
freddiefujiwara

1
设置window.location会更改浏览器,因此不会发生。
epascarello

1
嗯,是的。window.location不是字符串,但是可以从字符串中分配。我不确定是否可以模仿,我曾尝试将位置原型分配给新的uri对象,但这没有用。
Rex M

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,您将了解为什么简单的正则表达式无法将其截断。现在向它扔一些无效的东西,它也应该以可预见的方式摆脱困境。
Mikko Rantalainen

简单的正则表达式用于解决简单的问题:)但是,对于我来说,听起来像这样的url不是正则表达式无法解析的,它只需要进行一些其他调整即可。但是,如果我需要更复杂和更精简的东西,我可能会去一些图书馆。
svestka,

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: "" }

希望我的第一份贡献对您有帮助!


重复的答案
Martin van Driel '18

6
是的,但最高层的人只是在2017年更新了awser,我在2016
。– A. Moynet

啊,我不好,对不起
Martin van Driel

9

这是我从https://gist.github.com/1847816复制的版本,但已重写,因此更易于阅读和调试。将锚定数据复制到另一个名为“结果”的变量的目的是因为锚定数据很长,因此将有限数量的值复制到结果将有助于简化结果。

/**
 * 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中都无法正常工作。如果您向chrome传递无效(或空白)的url,它将始终返回调用脚本的主机。因此,在IE中您将获得空白,而在Chrome中您将获得本地主机(或其他名称)。

如果您尝试查看引荐来源网址,这是骗人的。您将要确保返回的主机位于原始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 2013年

不过,这会完全破坏相对网址!
lakenen 2014年

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服务,它将更加有角度
切尔诺夫2014年

3

使用模块模式的简单而强大的解决方案。这包括针对IE的修复,其中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

您还可以使用Locutus项目(以前的php.js)中的parse_url()函数。

码:

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
该网址对我不起作用,但我在这里找到了它github.com/hirak/phpjs/blob/master/functions/url/parse_url.js
Stan Quinn

@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和相对URL


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

@山茶树和葡萄树我更新了代码以正确处理userinfo子组件。感谢您的评论,我之前没有注意到这个问题
Nikolay

爱这个正则表达式
Kunal

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 2015年

4
URL并非总是(实际上几乎从不),但是URL解析起来非常棘手,RFC中有很多细节。最好使用已经被数千人使用和测试的库。
雨果·塞奎拉

只使用内置的内容,而不是让别人使用图书馆来重新发明轮子怎么样?参见stackoverflow.com/a/24006120/747739
Phil

内置功能不支持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

一个简单的hack,第一个答案

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

即使没有参数也可以使用它来找出当前主机名 getLocation()。hostname将给出当前主机名

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.