Comment analyser une URL en nom d'hôte et chemin en javascript?


380

Je voudrais prendre une ficelle

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

et le transformer en un objet tel que

a.hostname == "example.com"

et

a.pathname == "/aa/bb"

11
Dans le cas où vous travaillez sur l'URL actuelle, vous pouvez accéder hostnameet pathnamedirectement à partir de l' locationobjet.
rvighne

1
qu'en est-il de "lastPathPart"?
Victor

Pas regex mais le module Python tldextract fait exactement cela: github.com/john-kurkowski/tldextract
Oliver Oliver

Réponses:


398

La manière moderne:

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

Renvoie un objet avec des propriétés hostnameet pathname, avec quelques autres .

Le premier argument est une URL relative ou absolue; s'il est relatif, vous devez spécifier le deuxième argument (l'URL de base). Par exemple, pour une URL relative à la page actuelle:

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

En plus des navigateurs, cette API est également disponible dans Node.js depuis la v7, à travers require('url').URL.


7
Agréable! Les URL relatives le cassent cependant ... :( new URL('/stuff?foo=bar#baz')->SyntaxError: Failed to construct 'URL': Invalid URL
lakenen

56
Technologie expérimentale: IE ne supporte pas cela! developer.mozilla.org/en-US/docs/Web/API/URL/…
cwouter

10
@cwouter: Cela fonctionne cependant dans Edge, qui remplace IE
rvighne

4
c'est la façon de le faire, edge a déjà 3 versions au dessus de ie donc ça n'a pas d'importance
Claudiu Creanga

7
Le fait que JavaScript n'ait pas de méthode intégrée pour analyser les URL qui fonctionne sur les navigateurs ou les serveurs est assez triste ...
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
Êtes-vous sûr qu'il s'agit d'une solution compatible avec tous les navigateurs?
cllpse le

70
Il convient de noter que, bien que cela puisse aider / répondre à l'affiche originale, cette réponse ne fonctionnera que pour les personnes effectuant un travail JS dans un navigateur, car il dépend du DOM pour faire son travail.
Adam Batkin

4
Un autre exemple de simplicité, à côté de l'ingéniosité.
Saeed Neamati

26
Ne fonctionne pas dans IE si le href est relatif. l.hostname sera vide. Si vous ne fournissez que des URL complètes, cela fonctionnera.
Derek Prior

7
Même avec des URL absolues, IE (testé dans IE 11) se comporte différemment de Chrome et Firefox. IE pathnamesupprime la barre oblique principale, contrairement aux autres navigateurs. Vous vous retrouverez donc avec /pathou path, selon votre navigateur.
TrueWill du

299

trouvé ici: 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
Notez que si vous souhaitez simplement obtenir les parties analysées de l'emplacement actuel du navigateur, les deux premières lignes deviennent parser = location;et toutes les lignes suivantes fonctionnent. Je l'ai essayé dans Chrome et IE9 tout à l'heure.
Lee Meador

9
Notez également que pathnamen'inclut pas la barre oblique principale dans IE. Allez comprendre. : D
nevelis

3
Pour IE, utilisez "/" + parser.pathname
sbose

Attention: il reviendra http:même si vous passez juste domain.comen href (sans aucun protocole). Je voulais l'utiliser pour vérifier si le protocole manquait, et si c'est le cas, je pourrais l'ajouter, mais il suppose que http: n'a donc pas pu l'utiliser à cette fin.
Max Hodges

Le nom d'hôte inclut en fait le protocole. Testez la dernière version de Chrome.
AndroidDev

109

Voici une fonction simple utilisant une expression rationnelle qui imite le acomportement des balises.

Avantages

  • comportement prévisible (aucun problème de navigateur croisé)
  • n'a pas besoin du DOM
  • c'est vraiment court.

Les inconvénients

  • L'expression régulière est un peu difficile à lire

-

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

ÉDITER:

Voici une ventilation de l'expression régulière

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

4
Ne fonctionne avec aucune URL relative. Avez-vous suivi la RFC-3986 lors de la création de l'expression rationnelle? > getLocation ("// example.com/"); null> getLocation ("/ chemin d'accès /? recherche"); null> getLocation ("/ chemin d'accès /"); null> getLocation ("relative"); null
gregers

2
J'aime comment cela n'utilise pas le DOM, mais gregers a un bon point. Ce serait bien si cela pouvait gérer des chemins relatifs. Il faudrait utiliser window.location (un élément a) pour remplir les blancs et ajouter du code. Dans ce cas, la méthode deviendrait hypocrite. Sauf s'il existe une alternative, je ne sais pas comment cela peut être résolu parfaitement.
Turbo

Ajout de la clé href avec l'URL d'origine, cela assure la cohérence de cet objet de retour avec l'implémentation dom.
mattdlockyer

2
Si quelqu'un doit analyser des URL relatives, voici l'expression rationnelle mise à jour: / ^ (? :( https? \:) \ / \ /)? (([^: \ /? #] *) (?: \: ([0 -9] +))?) ([\ /] {0,1} [^? #] *) (\? [^ #] * |) (#. * |) $ /
shlensky

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

renvoie le currentUrl.

Si vous souhaitez passer votre propre chaîne sous forme d'URL ( ne fonctionne pas dans IE11 ):

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

Ensuite, vous pouvez l'analyser comme:

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

La réponse de freddiefujiwara est assez bonne, mais j'avais également besoin de prendre en charge les URL relatives dans Internet Explorer. J'ai trouvé la solution suivante:

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

Maintenant, utilisez-le pour obtenir les propriétés nécessaires:

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

Exemple JSFiddle: http://jsfiddle.net/6AEAB/


4
Ce devrait être la réponse acceptée. Utilisation très intelligente de la gestion d'URL relative à absolue. +1
L0j1k

Apparemment, ce n'est pas la première fois qu'un lien JSFiddle meurt: stackoverflow.com/questions/25179964/…
Claus

3
Cela a très bien fonctionné, mais j'ai eu une mise à jour qui, j'espère, aidera les autres. J'utilise ceci pour vérifier l'origine sur une demande postMessage et lorsque le port est un port par défaut (80 ou 443), il n'est pas ajouté au chemin. J'ai vérifié sous condition lors de la création de mon URL: var locationHost = (location.port !== '80' && location.port !== '443') ? location.host : location.hostname; var locationOrigin = location.protocol + '//' + locationHost;
rhoster

2
J'ai fait ce commentaire ailleurs sur une variante plus populaire de cette solution, mais comme c'était ma solution préférée, je voulais la répéter ici. Dans IE11, avoir un nom d'utilisateur dans le href entraînera toutes ces lectures de propriété à jeter des erreurs de sécurité. Exemple: " example.com " fonctionnera très bien. Mais " username@www.example.com " ou " username: password@www.example.com " tentera de faire référence à l'une des autres propriétés de l'élément d'ancrage (exemple: hachage) pour échouer et générer une erreur odieuse.
Clippy

17

js-uri (disponible sur Google Code) prend une URL de chaîne et en résout un objet 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

Merci!!! mais je veux uri = new Location (" example.com/aa/bb" ) typeof (window.location) == typeof (uri)
freddiefujiwara

Puisque window.location est une chaîne, je ne vois pas vraiment comment cela serait possible ou utile. Pourquoi les types doivent-ils correspondre alors que vous pouvez facilement passer de l'un à l'autre?
Rex M

developer.mozilla.org/en/DOM/window.location est une très belle API !! j'espère donc convertir String en objet window.location
freddiefujiwara

1
La définition de window.location modifie le navigateur afin que cela ne se produise pas.
epascarello

1
Hmm c'est vrai. window.location n'est pas une chaîne, mais peut être attribué à partir d'une chaîne. Je ne sais pas si cela peut être imité, j'ai essayé d'assigner le prototype de l'emplacement à un nouvel objet uri mais cela n'a pas fonctionné.
Rex M

12

Qu'en est-il de l'expression régulière simple?

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

Essayez d'analyser quelque chose de valide comme //user:password@example.com/path/x?y=zet vous verrez pourquoi la simple expression régulière ne le coupe pas. Maintenant, jetez quelque chose d'invalide et il devrait également être renfloué de manière prévisible.
Mikko Rantalainen

Une regex simple est pour des problèmes simples :) Mais il ne me semble pas qu'une URL comme celle-ci ne soit pas analysable par regex, elle aurait juste besoin de quelques ajustements supplémentaires. Mais j'irais probablement pour une bibliothèque si j'ai besoin de quelque chose de plus complexe et de toit ouvrant.
svestka

12

aujourd'hui je rencontre ce problème et j'ai trouvé: URL - MDN Web APIs

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

Ce retour:

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

En espérant que ma première contribution vous aide!


Réponse en double
Martin van Driel

6
Ouais mais le gars au sommet vient de mettre à jour son awser en 2017, moi je le poste en 2016.
A. Moynet

Ah mon méchant, désolé
Martin van Driel

9

Voici une version que j'ai copiée à partir de https://gist.github.com/1847816 , mais réécrite afin qu'elle soit plus facile à lire et à déboguer. Le but de la copie des données d'ancrage dans une autre variable nommée "résultat" est parce que les données d'ancrage sont assez longues, et donc la copie d'un nombre limité de valeurs dans le résultat aidera à simplifier le résultat.

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

Analyse d'URL inter-navigateurs , contourne le problème de chemin relatif pour IE 6, 7, 8 et 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;
}

Utilisation ( démo JSFiddle ici ):

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

Résultat:

{
    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

Pour ceux qui recherchent une solution moderne qui fonctionne dans IE, Firefox et Chrome:

Aucune de ces solutions qui utilisent un élément de lien hypertexte ne fonctionnera de la même manière dans Chrome. Si vous transmettez une URL non valide (ou vide) à Chrome, elle renverra toujours l'hôte d'où le script est appelé. Donc, dans IE, vous obtiendrez vide, tandis que dans Chrome, vous obtiendrez localhost (ou autre).

Si vous essayez de regarder le référent, c'est trompeur. Vous voudrez vous assurer que l'hôte que vous récupérez était dans l'URL d'origine pour gérer cela:

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

C'est une chose très importante à considérer!
2rs2ts

Cela brise complètement les URL relatives, cependant!
lakenen

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>

2
Ce sera plus angulaire si vous utilisez $documentet $windowservices
Cherniv

3

Solution simple et robuste utilisant le modèle de module. Cela inclut un correctif pour IE où le pathnamen'a pas toujours une barre oblique ( /).

J'ai créé un Gist avec un JSFiddle qui offre un analyseur plus dynamique. Je vous recommande de le vérifier et de fournir des commentaires.

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

Démo

Production

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

Pourquoi ne l'utilisez pas?

        $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

Vous pouvez également utiliser la parse_url()fonction du projet Locutus (ancien php.js).

Code:

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

Résultat:

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

1
cette URL n'a pas fonctionné pour moi, mais je l'ai trouvée ici github.com/hirak/phpjs/blob/master/functions/url/parse_url.js
Stan Quinn

@StanQuinn, c'est parce que php.js a changé son nom en Locutus. J'ai mis à jour ma réponse avec un nouveau lien.
Andrey Rudenko

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

Il fonctionne avec des URL absolues et relatives


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

@ 山 茶树 和 葡萄 树 J'ai mis à jour le code pour gérer correctement le sous-composant userinfo. Merci pour votre commentaire, je n'ai pas remarqué ce problème avant
Nikolay

adore cette expression régulière
Kunal

2

Arrêtez de réinventer la roue. Utilisez 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
Parce que chaque fois que vous voulez résoudre un problème ... utilisez une bibliothèque? D'accord ... (pas)
jiminikiz

4
Pas toujours (en fait presque jamais) mais les URL sont très difficiles à analyser, il y a beaucoup de détails dans les RFC. Mieux vaut utiliser une bibliothèque qui a été utilisée et testée par des milliers.
Hugo Sequeira

Que diriez-vous d'utiliser simplement ce qui est intégré, au lieu d'avoir quelqu'un d'autre à réinventer la roue avec une bibliothèque? Voir stackoverflow.com/a/24006120/747739
Phil

Il n'y a pas de support IE11 pour la fonction intégrée, donc cette bibliothèque est excellente. Dire de ne jamais utiliser une bibliothèque, c'est comme dire que nous n'aurions jamais dû utiliser jQuery et simplement écrire du code natif, ce qui est absolument ridicule. Chaque développeur a un cas d'utilisation différent, il n'y a pas de «meilleur» moyen, parfois vanilla / native fonctionne mieux, parfois non ... quelque chose que 92% des développeurs doivent encore apprendre.
tno2007

1

Utilisez simplement la bibliothèque url.js (pour le web et 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

un simple hack avec la première réponse

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

ceci peut être utilisé même sans argument pour déterminer le nom d'hôte actuel getLocation (). hostname donnera le nom d'hôte actuel

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.