Come posso analizzare un URL in nome host e percorso in javascript?


379

Vorrei prendere una corda

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

e trasformarlo in un oggetto tale

a.hostname == "example.com"

e

a.pathname == "/aa/bb"

11
Nel caso in cui lavori sull'URL corrente, puoi accedere hostnamee pathnamedirettamente locationdall'oggetto.
rvighne,

1
che dire di "lastPathPart"?
Victor,

Non regex ma il modulo Python tldextract fa esattamente questo: github.com/john-kurkowski/tldextract
Oliver Oliver,

Risposte:


395

Il modo moderno:

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

Restituisce un oggetto con proprietà hostnamee pathname, insieme ad alcuni altri .

Il primo argomento è un URL relativo o assoluto; se è relativo, è necessario specificare il secondo argomento (l'URL di base). Ad esempio, per un URL relativo alla pagina corrente:

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

Oltre ai browser, questa API è disponibile anche in Node.js dalla v7 alla fine require('url').URL.


7
Bello! Gli URL relativi lo interrompono però ... :( new URL('/stuff?foo=bar#baz')->SyntaxError: Failed to construct 'URL': Invalid URL
lakenen il

56
Tecnologia sperimentale: IE non supporta questo! developer.mozilla.org/en-US/docs/Web/API/URL/…
cwouter

10
@cwouter: Funziona comunque con Edge, che sostituisce IE
rvighne,

4
questo è il modo di farlo, Edge ha già 3 versioni in cima, quindi non importa
Claudiu Creanga

7
Il fatto che JavaScript non abbia un modo integrato per analizzare gli URL che funzionano su browser o server è piuttosto 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
Sei sicuro che si tratti di una soluzione compatibile con più browser?
cllpse

70
Va notato che, sebbene ciò possa aiutare / rispondere al poster originale, questa risposta funzionerà solo per le persone che fanno JS in un browser, poiché si affida al DOM per fare il suo lavoro.
Adam Batkin,

4
Un altro esempio di semplicità, insieme all'ingegno.
Saeed Neamati,

26
Non funziona in IE se l'href è relativo. l.hostname sarà vuoto. Se stai fornendo solo URL completi, allora funzionerà.
Derek prima del

7
Anche con URL assoluti, IE (testato in IE 11) si comporta diversamente da Chrome e Firefox. IE's pathnamerimuove la barra iniziale, mentre gli altri browser no. Quindi finirai con /patho path, a seconda del tuo browser.
TrueWill

299

trovato qui: 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
Si noti che se si desidera ottenere solo le parti analizzate della posizione corrente del browser, le prime due righe diventano parser = location;e tutte le righe seguenti funzionano. Ho provato in Chrome e IE9 proprio ora.
Lee Meador,

9
Si noti inoltre che pathnamenon include la barra iniziale in IE. Vai a capire. : D
nevelis,

3
Per IE, usa "/" + parser.pathname
sbose il

Attenzione: tornerà http:anche se passi solo domain.coma href (senza alcun protocollo). Volevo usarlo per verificare se mancava il protocollo e, in tal caso, potevo aggiungerlo, ma presuppone che http: quindi non ero in grado di usarlo per questo scopo.
Max Hodges,

Il nome host include effettivamente il protocollo. Prova sull'ultima versione di Chrome.
AndroidDev,

109

Ecco una semplice funzione che utilizza un regexp che imita il acomportamento del tag.

Professionisti

  • comportamento prevedibile (nessun problema tra browser)
  • non ha bisogno del DOM
  • è davvero corto.

Contro

  • Il regexp è un po 'difficile da leggere

-

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

MODIFICARE:

Ecco una ripartizione dell'espressione regolare

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

4
Non funziona con nessun URL relativo. Hai seguito RFC-3986 durante la regexp? > getLocation ("// example.com/"); null> getLocation ("/ nome percorso /? ricerca"); null> getLocation ("/ nome percorso /"); null> getLocation ("relative"); null
gregers

2
Mi piace come questo non usi il DOM, ma greger ha un buon punto. Sarebbe bello se questo potesse gestire percorsi relativi. Dovrebbe usare window.location (un elemento a) per riempire gli spazi vuoti e aggiungere codice. In tal caso, il metodo diventerebbe ipocrita. A meno che non ci sia un'alternativa, non sono sicuro di come questo possa essere risolto perfettamente.
Turbo

Aggiunta la chiave href con url originale, ciò fornisce coerenza su quell'oggetto return con l'implementazione dom.
mattdlockyer,

2
Se qualcuno deve analizzare gli URL relativi qui è il regexp aggiornato: / ^ (? :( https? \:) \ / \ /)? (([^: \ /? #] *) (?: \: ([0 -9] +))?) ([\ /] {0,1} [^? #] *) (\? [^ #] * |) (#. * |) $ /
shlensky

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

restituisce currentUrl.

Se vuoi passare la tua stringa come url ( non funziona in IE11 ):

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

Quindi puoi analizzarlo come:

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 risposta di freddiefujiwara è piuttosto buona, ma dovevo anche supportare gli URL relativi in ​​Internet Explorer. Ho trovato la seguente soluzione:

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

Ora usalo per ottenere le proprietà necessarie:

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

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


4
Questa dovrebbe essere la risposta accettata. Uso molto intelligente della gestione degli URL da relativa a assoluta. +1
L0j1k,

A quanto pare non è la prima volta che un link JSFiddle morto: stackoverflow.com/questions/25179964/...
Claus

3
Ha funzionato alla grande, tuttavia ho avuto un aggiornamento che spero possa aiutare gli altri. Sto usando questo per verificare l'origine su una richiesta postMessage e quando la porta è una porta predefinita (80 o 443), non viene aggiunta al percorso. L'ho verificato in modo condizionale quando ho creato il mio URL: var locationHost = (location.port !== '80' && location.port !== '443') ? location.host : location.hostname; var locationOrigin = location.protocol + '//' + locationHost;
rhoster

2
Ho fatto questo commento altrove su una variante più popolare di questa soluzione, ma poiché questa era la mia soluzione preferita, volevo ripeterlo qui. In IE11, avere un nome utente nell'href farà sì che tutte queste letture delle proprietà generino errori di sicurezza. Esempio: " example.com " funzionerà perfettamente. Ma " username@www.example.com " o " username: password@www.example.com " tenteranno di fare riferimento a una delle altre proprietà dell'elemento di ancoraggio (esempio: hash) per fallire e generare un errore odioso.
Clippy,

17

js-uri (disponibile su Google Code) accetta un URL stringa e risolve un oggetto URI da esso:

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

Grazie!!! ma voglio uri = new Location (" esempio.com/aa/bb" ) typeof (window.location) == typeof (uri)
freddiefujiwara

Dato che window.location è una stringa, non vedo davvero come sarebbe possibile o utile. Perché i tipi devono corrispondere quando è possibile convertire facilmente da uno all'altro?
Rex M

developer.mozilla.org/en/DOM/window.location è molto bello api !! quindi spero Conversione di stringhe in oggetto window.location
freddiefujiwara

1
L'impostazione di window.location modifica il browser in modo che non accada.
epascarello,

1
Hmm, è vero. window.location non è una stringa, ma può essere assegnata da una stringa. Non sono sicuro che possa essere imitato, ho provato ad assegnare il prototipo di posizione a un nuovo oggetto uri ma non ha funzionato.
Rex M

12

Che dire della semplice espressione regolare?

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

Prova ad analizzare qualcosa di valido come //user:password@example.com/path/x?y=ze vedrai perché la semplice espressione regolare non lo taglia. Ora lancia qualcosa di non valido e dovrebbe salvarsi anche in modo prevedibile.
Mikko Rantalainen,

La semplice regex è per semplici problemi :) Ma non mi sembra che l'URL come questo non sia analizzabile da regex, avrebbe solo bisogno di qualche altra modifica. Ma probabilmente andrei in qualche biblioteca se avessi bisogno di qualcosa di più complesso e proiettile.
svestka,

12

oggi incontro questo problema e ho trovato: URL - API Web MDN

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

Questo ritorno:

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

Spero che il mio primo contributo ti aiuti!


Risposta duplicata
Martin van Driel,

6
Sì, ma il ragazzo in cima aggiorna il suo stupido nel 2017, io lo pubblico nel 2016.
A. Moynet,

Ah mio male, scusa
Martin van Driel,

9

Ecco una versione che ho copiato da https://gist.github.com/1847816 , ma riscritta in modo che sia più facile da leggere ed eseguire il debug. Lo scopo di copiare i dati di ancoraggio in un'altra variabile denominata "risultato" è perché i dati di ancoraggio sono piuttosto lunghi, e quindi copiare un numero limitato di valori nel risultato aiuterà a semplificare il risultato.

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

Analisi degli URL tra browser , aggira il problema relativo al percorso per IE 6, 7, 8 e 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;
}

Utilizzo ( demo JSFiddle qui ):

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

Risultato:

{
    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

Per coloro che cercano una soluzione moderna che funzioni in Internet Explorer, Firefox e Chrome:

Nessuna di queste soluzioni che utilizzano un elemento hyperlink funzionerà allo stesso modo in Chrome.Se passi un URL non valido (o vuoto) a Chrome, restituirà sempre l'host da cui viene chiamato lo script. Quindi in IE diventerai vuoto, mentre in Chrome otterrai localhost (o qualsiasi altra cosa).

Se stai cercando di guardare il referrer, questo è ingannevole. Dovrai assicurarti che l'host che ricevi sia nell'URL originale per gestire questo:

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

Questa è una cosa molto importante da considerare!
ore 2

Questo però interrompe completamente gli URL relativi!
Lakenen,

4

The AngularJS way - violino qui: 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
Sarà più angolare se userete $documente $windowservizi
Cherniv,

3

Soluzione semplice e robusta che utilizza il modello di modulo. Ciò include una correzione per IE in cui pathnamenon sempre è presente un forward-slash ( /).

Ho creato un Gist insieme a un JSFiddle che offre un parser più dinamico. Ti consiglio di dare un'occhiata e fornire 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);

dimostrazione

Produzione

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

Perché non usarlo?

        $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

È inoltre possibile utilizzare la parse_url()funzione dal progetto Locutus (ex php.js).

Codice:

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

Risultato:

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

1
quell'URL non ha funzionato per me, ma l'ho trovato qui github.com/hirak/phpjs/blob/master/functions/url/parse_url.js
Stan Quinn,

@StanQuinn, perché php.js ha cambiato il nome in Locutus. Ho aggiornato la mia risposta con un nuovo link.
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");

Funziona con URL sia assoluti che relativi


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

@ 山 茶树 和 葡萄 树 Ho aggiornato il codice per gestire correttamente il sottocomponente userinfo. Grazie per il tuo commento, non avevo notato questo problema prima
Nikolay

Adoro questo regex
Kunal

2

Smetti di reinventare la ruota. Usa 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
Perché ogni volta che vuoi risolvere un problema ... usa una libreria? Okay ... (no)
jiminikiz,

4
Non sempre (in realtà quasi mai) ma gli URL sono molto difficili da analizzare, ci sono molti dettagli negli RFC. Meglio usare una libreria che è stata utilizzata e testata da migliaia.
Hugo Sequeira,

Che ne dici di usare solo ciò che è incorporato, invece di avere qualcun altro a reinventare la ruota con una libreria? Vedi stackoverflow.com/a/24006120/747739
Phil

Non esiste un supporto IE11 per la funzione integrata, quindi questa libreria è eccellente. Dire di non usare mai una libreria è come dire che non avremmo mai dovuto usare jQuery e scrivere semplicemente codice nativo, il che è assolutamente ridicolo. Ogni sviluppatore ha un caso d'uso diverso, non esiste un modo "migliore", a volte vaniglia / nativo funziona meglio, a volte no ... qualcosa che il 92% degli sviluppatori deve ancora imparare.
tno2007,

1

Usa la libreria url.js (per web e 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 semplice trucco con la prima risposta

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

questo può essere usato anche senza argomenti per capire il nome host attuale getLocation (). hostname fornirà il nome host corrente

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.