504

I would like to take a string

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

and process it into an object such that

a.hostname == "example.com"

and

a.pathname == "/aa/bb"
hakre
  • 193,403
  • 52
  • 435
  • 836
freddiefujiwara
  • 57,041
  • 28
  • 76
  • 106

26 Answers26

597

The modern way:

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

Returns an object with properties hostname and pathname, along with a few others.

The first argument is a relative or absolute URL; if it's relative, then you need to specify the second argument (the base URL). For example, for a URL relative to the current page:

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

In addition to browsers, this API is also available in Node.js since v7, through require('url').URL.

rvighne
  • 20,755
  • 11
  • 51
  • 73
  • 1
    The only problem is now you have to parse whether it's relative or absolute yourself. IMO this should just be handled by `URL`. Maybe we can get it into the spec? :P – lakenen Jun 26 '14 at 18:29
  • 1
    The relative part is a separate argument rather than concatenation. eg: new URL( path, baseURL ) – Adria Nov 15 '14 at 18:44
  • 62
    Experimental technology: IE doens't support this! https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#Browser_compatibility – cwouter Mar 18 '15 at 15:08
  • 14
    @cwouter: It does work in Edge however, which replaces IE – rvighne Jun 24 '16 at 20:35
  • 4
    this is the way to do it, edge is already 3 versions on top of ie so it doesn't matter – Claudiu Creanga Aug 24 '16 at 19:27
  • 4
    @justingordon: The `URL` class is a Web standard, so non-browsers aren't required to implement it. However, recent versions of Nodejs do provide an identical library, [`require('url').URL`](https://nodejs.org/api/url.html#url_the_whatwg_url_api) – rvighne May 19 '17 at 04:25
  • This does not get you the domain. It will return the protocol as part of the domain. – Johann Aug 23 '17 at 15:41
  • 1
    @AndroidDev: How did you use it? `new URL("https://stackoverflow.com/questions/736513/how-do-i-parse-a-url-into-hostname-and-path-in-javascript").host`? – serv-inc Dec 02 '17 at 11:22
  • 1
    @rvighne I feel like it's important to note that there is no support for this on IE11 and below https://caniuse.com/#search=url – benwsmith Mar 27 '18 at 17:10
  • 14
    The fact that JavaScript doesn't have a built-in way to parse URLs that works on browsers or servers is pretty sad... – Skitterm Apr 25 '18 at 00:24
  • 2
    @Skitterm it's pretty ironic that this is the case. – Nik Barres Feb 07 '19 at 16:23
  • This should be way higher, a great answer that works in any environment (or at least for my purposes lol)! And most importantly, it's modern. – Matthew Ludwig Aug 01 '19 at 01:58
  • Why is this so far down? It has the most upvotes even. StackOverflow is weird nowadays. – mxcl Aug 02 '21 at 13:36
  • It is better to use try block if the URL is a variable. new URL throws catchable exception if the string is not a valid URL try { url = new URL(theInputURL) } catch (_) { //catch error } – Nafsin Vk Sep 06 '22 at 10:46
383
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"
aehlke
  • 15,225
  • 5
  • 36
  • 45
freddiefujiwara
  • 57,041
  • 28
  • 76
  • 106
  • 15
    Are you sure this is a cross-browser compatible solution? – cllpse Apr 10 '09 at 09:55
  • href is a special DOM attribute type with those additional URI-like properties on it. Very interesting! – Rex M Apr 10 '09 at 16:59
  • 76
    It should be noted that, while this may help/answer the original poster, this answer will only work for people doing JS work in a browser, since it relies on the DOM to do its work. – Adam Batkin Aug 01 '09 at 22:21
  • 5
    Another example of simplicity, alongside ingenuity. – Saeed Neamati Feb 21 '12 at 13:50
  • 28
    Does not work in IE if the href is relative. l.hostname will be empty. If you're only providing full URL's then this will work. – Derek Prior Sep 06 '12 at 18:21
  • If you need relative URL support in IE, check out Claus's answer. – Azmisov Jul 03 '13 at 04:16
  • This doesn't work in chrome. Anytime you pass anything invalid, you get the calling domain back. So if there no referrer it looks like a self referral. – KingOfHypocrites Nov 05 '13 at 23:59
  • 7
    Even with absolute URLs, IE (tested in IE 11) behaves differently from Chrome and Firefox. IE's `pathname` removes the leading slash, while the other browsers do not. So you'll end up with `/path` or `path`, depending on your browser. – TrueWill Apr 09 '15 at 19:00
  • here is my usl: `www.example.com/contact#test` how can I get `test` ? – Shafizadeh Jul 20 '15 at 18:47
  • @Sajad, if you are looking for a front-end solution, and the url in question is the url of the page you are on, `location.hash` is all of you need. Else, look at @Rems answer below. – jiminikiz Sep 29 '15 at 22:48
  • 1
    as @AdamBatkin noted, without DOM this won't work.. which means it's a no-go in Service Workers as well. – Chris Ruppel Dec 07 '15 at 06:56
  • In IE11, having a username in the href will cause all these property reads to throw security errors. Example: "http://www.example.com" will work just fine. But "http://username@www.example.com" or "http://username:password@www.example.com" will make any attempt to reference one of the other properties of the anchor element (example: hash) to fail and throw an obnoxious error. – Clippy Oct 17 '16 at 04:43
  • Check docs for Browser compatibility: https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname – andistuder Aug 09 '17 at 09:35
  • 1
    IE11 appends the SSL port to the `host` property `"google.com:443"`, may cause inconsistencies – Andy Polhill Jan 15 '18 at 08:56
  • 1
    This answer is outdated. Can you please change the accepted answer to be the one that uses the new URL API? – Andrew Rondeau Dec 14 '18 at 16:50
  • This caused me a lot of problems with internet explorer since I used the result for a regex. Here is a fix to make it coherent across the browsers: `var pathname = l.pathname.replace(/(\/)?/, '/');` – Christian Vincenzo Traina Apr 01 '19 at 09:51
  • @freddiefujiwara I didn't edit, but consider to add the fix in the answer – Christian Vincenzo Traina Apr 01 '19 at 09:51
  • If you dont need to manipulate host or protocol, just use origin – Noman_1 Feb 10 '22 at 12:39
331

found here: 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"
B T
  • 57,525
  • 34
  • 189
  • 207
Joseph Oster
  • 5,507
  • 1
  • 20
  • 11
135

Here's a simple function using a regexp that imitates the a tag behavior.

Pros

  • predictable behaviour (no cross browser issues)
  • doesn't need the DOM
  • it's really short.

Cons

  • The regexp is a bit difficult to read

-

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"
}
*/

EDIT:

Here's a breakdown of the regular expression

var reURLInformation = new RegExp([
    '^(https?:)//', // protocol
    '(([^:/?#]*)(?::([0-9]+))?)', // host (hostname and port)
    '(/{0,1}[^?#]*)', // pathname
    '(\\?[^#]*|)', // search
    '(#.*|)$' // hash
].join(''));
var match = href.match(reURLInformation);
mattdlockyer
  • 6,984
  • 4
  • 40
  • 44
Rems
  • 4,837
  • 3
  • 27
  • 24
  • 4
    Doesn't work with any relative URLs. Did you follow RFC-3986 when making the regexp? > getLocation("//example.com/"); null > getLocation("/pathname/?search"); null > getLocation("/pathname/"); null > getLocation("relative"); null – gregers May 07 '14 at 08:26
  • 2
    I like how this does not use the DOM, but gregers has a good point. It would be nice if this can handle relative paths. It would require to use window.location (an a element) to fill in the blanks and adding code. In that case, the method would become hypocritical. Unless there is an alternative, not sure how this can be solved perfectly. – Turbo Sep 24 '14 at 22:11
  • Added the href key with original url, this provides consistency on that return object with the dom implementation. – mattdlockyer Apr 11 '17 at 14:29
  • 2
    If someone need to parse relative URLs here is the updated regexp: /^(?:(https?\:)\/\/)?(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/ – shlensky Apr 03 '18 at 21:33
103
var loc = window.location;  // => "http://example.com:3000/pathname/?search=test#hash"

returns the currentUrl.

If you want to pass your own string as a url (doesn't work in IE11):

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

Then you can parse it like:

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"
cslecours
  • 164
  • 8
Peter Graham
  • 2,467
  • 2
  • 24
  • 29
66

freddiefujiwara's answer is pretty good but I also needed to support relative URLs within Internet Explorer. I came up with the following solution:

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;
};

Now use it to get the needed properties:

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

Example:

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 urlToParse = 'http://example.com/aa/bb/',
  a = getLocation(urlToParse);
document.write('Absolute URL: ' + urlToParse);
document.write('<br />');
document.write('Hostname: ' + a.hostname);
document.write('<br />');
document.write('Pathname: ' + a.pathname);
AuRise
  • 2,253
  • 19
  • 33
Claus
  • 1,684
  • 14
  • 20
  • 4
    This should be the accepted answer. Very clever use of relative-to-absolute URL handling. +1 – L0j1k May 30 '14 at 16:52
  • Apparently not the first time a JSFiddle link died: http://stackoverflow.com/questions/25179964/my-jsfiddle-page-returns-404-registration-required – Claus Feb 04 '16 at 03:55
  • 3
    This worked great, however I had one update that I hope will help others. I'm using this to check origin on a postMessage request and when the port is a default port (80 or 443), it doesn't get appended to the path. I conditionally checked for that when creating my URL: `var locationHost = (location.port !== '80' && location.port !== '443') ? location.host : location.hostname;` `var locationOrigin = location.protocol + '//' + locationHost;` – Bobby Oster Apr 07 '16 at 22:58
  • 3
    I made this comment elsewhere on a more popular variant of this solution, but as this was my favorite solution, I wanted to repeat it here. In IE11, having a username in the href will cause all these property reads to throw security errors. Example: "http://www.example.com" will work just fine. But "http://username@www.example.com" or "http://username:password@www.example.com" will make any attempt to reference one of the other properties of the anchor element (example: hash) to fail and throw an obnoxious error. – Clippy Oct 17 '16 at 04:42
  • fantastic solution! – Christian Haller Aug 12 '21 at 11:32
18

js-uri (available on Google Code) takes a string URL and resolves a URI object from it:

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
Rex M
  • 142,167
  • 33
  • 283
  • 313
  • thanks!!! but I want to uri = new Location("http://example.com/aa/bb") typeof(window.location) == typeof(uri) – freddiefujiwara Apr 10 '09 at 02:30
  • Since window.location is a string, I don't really see how that would be possible or helpful. Why do the types need to match when you can easily convert from one to the other? – Rex M Apr 10 '09 at 02:33
  • https://developer.mozilla.org/en/DOM/window.location is very nice api!! so I hope convert String to window.location object – freddiefujiwara Apr 10 '09 at 02:48
  • 1
    Setting window.location changes the browser so it is not going to happen. – epascarello Apr 10 '09 at 03:06
  • 1
    Hmm that's right. window.location is not a string, but can be assigned from a string. I'm not sure if that can be mimicked, I've tried assigning the prototype of location to a new uri object but that did not work. – Rex M Apr 10 '09 at 03:53
  • Thank you for an opinion. Would you teach the source code that you tried? – freddiefujiwara Apr 10 '09 at 04:20
  • Keep in mind that this has bugs in it: no IPv6 support and it breaks when an `@` is present after the hostname. – Sam Apr 25 '13 at 01:08
13

What about simple regular expression?

url = "http://www.example.com/path/to/somwhere";
urlParts = /^(?:\w+\:\/\/)?([^\/]+)(.*)$/.exec(url);
hostname = urlParts[1]; // www.example.com
path = urlParts[2]; // /path/to/somwhere
svestka
  • 755
  • 1
  • 8
  • 13
  • Try to parse something valid like `//user:password@example.com/path/x?y=z` and you will see why simple regular expression does not cut it. Now throw something invalid to it and it should bail out in predictable way, too. – Mikko Rantalainen Oct 02 '19 at 05:51
  • Simple regex is for simple problems :) But it doesn't sound to me that url like this is unparsable by regex, it would just need few more tweaks. But I'd probably go for some library if I need something more complex and bulletroof though. – svestka Oct 03 '19 at 06:55
  • 1
    I agree with @svestka's comments above, but if you want a simple regex solution and have a trusted source (like I do) and no access to the DOM or URL() (as I'm using tabris.js) then a regex can be the way to go. Here's one that can handle the query string too `^(?:\w+\:\/\/)?([^\/]+)([^\?]*)\??(.*)$` – Luke Cousins Oct 16 '20 at 10:31
13

today I meet this problem and I found: URL - MDN Web APIs

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

This return:

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

Hoping my first contribution helps you !

A. Moynet
  • 450
  • 3
  • 8
11
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 r;
};
parseUrl("http://username:password@localhost:257/deploy/?asd=asd#asd");

It works with both absolute and relative urls

Nikolay
  • 309
  • 2
  • 8
  • `abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1` – 山茶树和葡萄树 Dec 03 '18 at 06:53
  • @山茶树和葡萄树 I have updated the code to handle userinfo subcomponent properly. Thanks for your comment, I didn't notice that problem before – Nikolay Dec 04 '18 at 10:40
  • love this regex – Kunal Jul 12 '19 at 19:06
  • nice regex! what I miss is pathname without parameters, preferable also any file separated . I did solve that with an additional regex, so there is no urgent need, but it's just a proposition. – David Sep 30 '20 at 18:52
  • filename and filesuffix could be still separated too. – David Sep 30 '20 at 18:58
  • @Nikolay b.xxx.xx.xx.xxx.com:5388 not work, can not get hostname – Michael Mao Nov 02 '21 at 03:53
  • 1
    @MichaelMao That's because absolute urls should always have scheme defined. Anyway I've updated regexp to handle such pseudo-absolute urls, so this is not a problem now. I have no enough time to test this regexp using wide range of urls, but I believe all should works fine. – Nikolay Feb 13 '22 at 17:02
  • @Nikolay very nice! One small bug, if there is a username but no password (such as "git@myhost.com"), then the hostname field will include the username, and the username field will be blank. – Brett Mar 25 '23 at 17:06
  • 1
    @Brett I've updated the code and it should work fine now – Nikolay Mar 28 '23 at 18:08
10

Here is a version that I copied from https://gist.github.com/1847816, but rewritten so it's easier to read and debug. The purpose of copying the of the anchor data to another variable named "result" is because the anchor data is pretty long, and so copying a limited number of values to the result will help simplify the 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;

}
pstenstrm
  • 6,339
  • 5
  • 41
  • 62
Biagio Arobba
  • 1,075
  • 11
  • 27
7

Cross-browser URL parsing, works around the relative path problem for IE 6, 7, 8 and 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;
}

Usage (demo JSFiddle here):

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

Result:

{
    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
  • 132,397
  • 37
  • 331
  • 304
5

For those looking for a modern solution that works in IE, Firefox, AND Chrome:

None of these solutions that use a hyperlink element will work the same in chrome. If you pass an invalid (or blank) url to chrome, it will always return the host where the script is called from. So in IE you will get blank, whereas in Chrome you will get localhost (or whatever).

If you are trying to look at the referrer, this is deceitful. You will want to make sure that the host you get back was in the original url to deal with this:

    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
  • 9,316
  • 9
  • 47
  • 69
4

The AngularJS way - fiddle here: 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>
Joseph Oster
  • 5,507
  • 1
  • 20
  • 11
4

Expanded on acdcjunior solution by adding "searchParam" function
Mimicking the URL object, added "searchParam" to parse query string
Works for IE 6, 7, 8 9, 10, 11

USAGE - (JSFiddle Link)

// USAGE:
var myUrl = new ParsedUrl("http://www.example.com/path?var1=123&var2=abc#fragment");
console.log(myUrl);
console.log(myUrl.searchParam('var1'));
console.log(myUrl.searchParam('var2'));

OUTPUT - (JSFiddle Link)

{
  hash: "#fragment",
  host: "www.example.com:8080",
  hostname: "www.example.com",
  href: "http://www.example.com:8080/path?var1=123&amp;var2=abc#fragment",
  pathname: "/path",
  port: "80",
  protocol: "http:",
  search: "?var1=123&amp;var2=abc"
}

"123"
"abc"

CODE - (JSFiddle Link)

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://www.example.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;
  
  //search Params
  this.searchParam =  function(variable) {
    var query = (this.search.indexOf('?') === 0) ? this.search.substr(1) : this.search;
    var vars = query.split('&');
    for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split('=');
        if (decodeURIComponent(pair[0]) == variable) {
            return decodeURIComponent(pair[1]);
        }
    }
    console.log('Query variable %s not found', variable);
    return '';
    };
}
CodeCowboyOrg
  • 2,983
  • 1
  • 15
  • 12
3

You can also use parse_url() function from Locutus project (former php.js).

Code:

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

Result:

{
  scheme: 'http',
  host: 'hostname',
  user: 'username',
  pass: 'password',
  path: '/path',
  query: 'arg=value',
  fragment: 'anchor'
}
Andrey Rudenko
  • 1,271
  • 20
  • 34
3

Simple and robust solution using the module pattern. This includes a fix for IE where the pathname does not always have a leading forward-slash (/).

I have created a Gist along with a JSFiddle which offers a more dynamic parser. I recommend you check it out and provide feedback.

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);

Demo

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);

/* Main */
var out = document.getElementById('out');
var urls = [
  'https://www.example.org:5887/foo/bar?a=1&b=2#section-1',
  'ftp://www.files.com:22/folder?id=7'
];
var parser = new URLParser();
urls.forEach(function(url) {
  parser.parse(url);
  println(out, JSON.stringify(parser.toObj(), undefined, ' '), 0, '#0000A7');
});

/* Utility functions */
function print(el, text, bgColor, fgColor) {
  var span = document.createElement('span');
  span.innerHTML = text;
  span.style['backgroundColor'] = bgColor || '#FFFFFF';
  span.style['color'] = fgColor || '#000000';
  el.appendChild(span);
}
function println(el, text, bgColor, fgColor) {
  print(el, text, bgColor, fgColor);
  el.appendChild(document.createElement('br'));
}
body {
  background: #444;
}
span {
  background-color: #fff;
  border: thin solid black;
  display: inline-block;
}
#out {
  display: block;
  font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
  font-size: 12px;
  white-space: pre;
}
<div id="out"></div>

Output

{
 "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"
}
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
3

Use https://www.npmjs.com/package/uri-parse-lib for this

var t = parserURI("http://user:pass@example.com:8080/directory/file.ext?query=1&next=4&sed=5#anchor");
3

Why do not use it?

        $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
  • 89
  • 2
  • 5
2

Stop reinventing the wheel. Use 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");
Hugo Sequeira
  • 474
  • 4
  • 10
  • 6
    Because every time you want to solve a problem... use a library? Okay... (not) – jiminikiz Sep 29 '15 at 22:44
  • 4
    Not always (actually almost never) but URLs are very tricky to parse, there are many many details in the RFCs. Better to use a library that has been used and tested by thousands. – Hugo Sequeira Oct 04 '15 at 22:12
  • 1
    How about just use what is built in, instead of having someone else reinvent the wheel with a library? See https://stackoverflow.com/a/24006120/747739 – Phil Jan 31 '19 at 20:52
  • There is no IE11 support for the built-in function, so this library is excellent. To say never to use a library is like saying we should never have used jQuery and just write native code, which is absolutely ridiculous. Every developer has a different use case, there is no 'best' way, sometimes vanilla/native works best, sometimes it doesn't... something 92% of developers still has to learn. – tno2007 Mar 04 '20 at 11:58
1

Just use url.js library (for web and 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...
Rob
  • 10,851
  • 21
  • 69
  • 109
1

a simple hack with the first answer

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

this can used even without argument to figure out the current hostname getLocation().hostname will give current hostname

sooraj
  • 324
  • 1
  • 8
1

This doesn't parse the query and hash, but otherwise it works well otherwise.

const getURIParts = (url) => {
  const matches = url.match(/^(\w+?:\/\/)?([\w-\.]+(?=\/?))?:?(\d*)?([^:]*)/)
  return {
    scheme: matches ? matches[1] : undefined,
    host: matches ? matches[2] : '',
    port: matches ? matches[3] : undefined,
    pathname: matches ? matches[4] : ''
  }
}

console.log(getURIParts(""))
console.log(getURIParts("http://localhost/bla"))
console.log(getURIParts("https://api.spotify.com/"))
console.log(getURIParts("https://api.spotify.com"))
console.log(getURIParts("wss://wss.slack.com/link/?ticket=1234-5678"))
console.log(getURIParts("localhost"))
console.log(getURIParts("localhost/bla"))
console.log(getURIParts("localhost/"))
console.log(getURIParts("api.spotify.com/bla/two"))
console.log(getURIParts("api.spotify.com:8000/bla/two"))
console.log(getURIParts("https://api.spotify.com:8800/"))
console.log(getURIParts("/mp3-preview/f504e6b8e037771318656394f532dede4f9bcaea"))
2upmedia
  • 2,832
  • 1
  • 20
  • 16
1

Of course in >2016 the right answer is using URL API
For page URL window.location
And for <a href="..."> HTMLAnchorElement API

Also for supporting older browser, using polyfill:

<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=URL"></script>

But just as an other option, it can be handle easy and accurate by RegEx pattern:

function URIinfo(s) {
    s=s.match(/^(([^/]*?:)\/*((?:([^:]+):([^@]+)@)?([^/:]{2,}|\[[\w:]+])(:\d*)?(?=\/|$))?)?((.*?\/)?(([^/]*?)(\.[^/.]+?)?))(\?.*?)?(#.*)?$/);
    return {origin:s[1],protocol:s[2],host:s[3],username:s[4],password:s[5],hostname:s[6],port:s[7],path:s[8],folders:s[9],file:s[10],filename:s[11],fileext:s[12],search:s[13],hash:s[14]};
}

var sample='http://user:password@my.site.com:8080/onefolder/folder.name/file.min.js?query=http://my.site.com:8080/file.exe#hash-root:/file/1.txt';

console.log (URIinfo(sample));
/*
{
  "origin": "http://user:password@my.site.com:8080",
  "protocol": "http:",
  "host": "user:password@my.site.com:8080",
  "username": "user",
  "password": "password",
  "hostname": "my.site.com",
  "port": ":8080",
  "path": "/onefolder/folder.name/file.min.js",
  "folders": "/onefolder/folder.name/",
  "file": "file.min.js",
  "filename": "file.min",
  "fileext": ".js",
  "search": "?query=http://my.site.com:8080/file.exe",
  "hash": "#hash-root:/file/1.txt"
}
*/

Work with the RegEx

It is fine with any kind of

  • Absolute / Relative paths
  • IPv4 / IPv6
  • Net protocols / Local Files
  • Query / Hash

And will return all URL options but not searchParams

(+) Also will return file info like PHP pathInfo

MMMahdy-PAPION
  • 915
  • 10
  • 15
0

Try This :

function getUrlPath(str){
//fakepath when url not have a path
  var fakepath = "/FakPath";
  var url = str+fakepath;
  var reg = /.+?\:\/\/.+?(\/.+?)(?:#|\?|$)/;
  var output = reg.exec(url);
  // check "output" != null
  return (output) ? output[1].replace(fakepath,"") : fakepath;
}

var myurl = "https://stackoverflow.com/questions/736513/";
const path = getUrlPath(myurl);

console.log(   path     );
//output :  /questions/736513/
borma425
  • 336
  • 5
  • 17
0

How about?

'https://stackoverflow.com/questions/736513/how-do-i-parse-a-url-into-hostname-and-path-in-javascript'.split('//').pop().split('/')[0]

Resulting:

'stackoverflow.com'

Taufik Nur Rahmanda
  • 1,862
  • 2
  • 20
  • 36