2009-01-22 3 views
74

Ich bin derzeit die folgende Funktion zu ‚konvertieren‘ eine relative URL auf einen absoluten einen mit:Abrufen einer absoluten URL von einer relativen URL. (IE6 Ausgabe)

function qualifyURL(url) { 
    var a = document.createElement('a'); 
    a.href = url; 
    return a.href; 
} 

Diese in den meisten Browsern funktioniert ganz gut, aber IE6 besteht nach wie vor die relative URL auf Rückkehr! Es tut dasselbe, wenn ich getAttribute ('href') verwende.

Die einzige Möglichkeit, eine qualifizierte URL aus IE6 zu erhalten, besteht darin, ein img-Element zu erstellen und dessen 'src'-Attribut abzufragen - das Problem dabei ist, dass es eine Serveranfrage erzeugt; etwas, das ich vermeiden möchte.

Also meine Frage ist: Gibt es eine Möglichkeit, eine voll qualifizierte URL in IE6 von einem relativen (ohne eine Server-Anfrage) zu erhalten?


Bevor Sie eine schnelle Regex/String-Fix empfehlen, versichere ich Ihnen, es ist nicht so einfach. Basiselemente + doppelte relative URLs + eine Tonne anderer potentieller Variablen machen es wirklich zur Hölle!

Es muss einen Weg geben, es zu tun, ohne ein Mammut aus einer Regex'y-Lösung zu erstellen ??

+8

Süße Hack! Es interessiert mich nicht für IE6. Sparte mir Stunden. Du schaukelst. –

+1

Sie könnten [js-uri] (http://code.google.com/p/js-uri/) verwenden, um den relativen URI in einen absoluten aufzulösen. – Gumbo

+0

Danke Gumbo, ich nehme an, das wird reichen müssen. Ich hätte mir eine prägnantere Lösung gewünscht, aber danke trotzdem, ich habe nie gewusst, dass diese js-uri Klasse existiert hat! – James

Antwort

0

Wenn url nicht mit ‚/‘ der aktuellen Seite url, abhacken

Nehmen Sie alles beginnt nach dem letzten ‚/‘; Dann hänge die relative URL an.

Else wenn url mit ‚/‘ beginnt

Nehmen Sie die URL der aktuellen Seite und hacken alles rechts von der Single ‚/‘ ab; Dann hänge die URL an.

Sonst wenn url beginnt mit # oder?

Nehmen Sie die URL der aktuellen Seite und fügen Sie einfach url


Hoffe, dass es für Sie

arbeitet
+2

Sie haben vergessen, dass URLs mit "//" beginnen können, was sie schemrelativ macht. //foo.com/bar/ –

+1

Sie haben auch die punktierte relative ../../ Syntax vergessen (ob diese Unterlassung zählt oder nicht hängt davon ab, was die Ausgabe erforderlich ist) – hallvors

46

Wie seltsam! IE versteht es jedoch, wenn Sie innerHTML anstelle von DOM-Methoden verwenden.

function escapeHTML(s) { 
    return s.split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;'); 
} 
function qualifyURL(url) { 
    var el= document.createElement('div'); 
    el.innerHTML= '<a href="'+escapeHTML(url)+'">x</a>'; 
    return el.firstChild.href; 
} 

Ein bisschen hässlich, aber prägnanter als Doing It Yourself.

+1

Diese Methode funktioniert gut für mich! Danke für das Posten! – zachleat

+0

Bestätigte Arbeit in IE7. – djsmith

+0

http://jsfiddle.net/z9MQE/ –

2

fand ich diesen Blog-Post, die ein Bild Element anstelle eines Ankers schlägt mit:

http://james.padolsey.com/javascript/getting-a-fully-qualified-url/

, die zuverlässig eine URL zu erweitern, auch in IE6 arbeitet an. Aber das Problem ist, dass die Browser, die ich getestet habe, die Ressource sofort nach dem Setzen des image src -Attributs herunterladen werden - selbst wenn Sie in der nächsten Zeile den src auf null setzen.

Ich werde stattdessen bolince Lösung geben.

27

Solange der Browser korrekt <Basis> Tag implementiert, welcher Browser ist in der Regel:

function resolve(url, base_url) { 
    var doc  = document 
    , old_base = doc.getElementsByTagName('base')[0] 
    , old_href = old_base && old_base.href 
    , doc_head = doc.head || doc.getElementsByTagName('head')[0] 
    , our_base = old_base || doc_head.appendChild(doc.createElement('base')) 
    , resolver = doc.createElement('a') 
    , resolved_url 
    ; 
    our_base.href = base_url || ''; 
    resolver.href = url; 
    resolved_url = resolver.href; // browser magic at work here 

    if (old_base) old_base.href = old_href; 
    else doc_head.removeChild(our_base); 
    return resolved_url; 
} 

Hier ist ein jsfiddle wo Sie damit experimentieren können: http://jsfiddle.net/ecmanaut/RHdnZ/

+0

waho, beste Antwort aller Zeiten. Ich wünschte, ich könnte 10 mal upvote. – Hartator

+0

Es ist drei Jahre zu spät zur Party, also wird es eine Weile dauern, bis es an die Spitze geht, ohne dass Marketing oder viele Leute das Problem haben und eine code-konservative und genaue Lösung wollen. – ecmanaut

+0

Besser spät als je zuvor. Ich denke, Ihre Lösung ist clever und robuster als die andere, auf den Browser zu vertrauen scheint der Weg zu sein. Auch wenn es als König von Hacky wahrgenommen werden könnte, Base-Tag zu injizieren. – Hartator

0

Wenn es im Browser läuft , diese Art von Arbeiten für mich ..

function resolveURL(url, base){ 
    if(/^https?:/.test(url))return url; // url is absolute 
    // let's try a simple hack.. 
    var basea=document.createElement('a'), urla=document.createElement('a'); 
    basea.href=base, urla.href=url; 
    urla.protocol=basea.protocol;// "inherit" the base's protocol and hostname 
    if(!/^\/\//.test(url))urla.hostname=basea.hostname; //..hostname only if url is not protocol-relative though 
    if(/^\//.test(url))return urla.href; // url starts with /, we're done 
    var urlparts=url.split(/\//); // create arrays for the url and base directory paths 
    var baseparts=basea.pathname.split(/\//); 
    if(! /\/$/.test(base))baseparts.pop(); // if base has a file name after last /, pop it off 
    while(urlparts[0]=='..'){baseparts.pop();urlparts.shift();} // remove .. parts from url and corresponding directory levels from base 
    urla.pathname=baseparts.join('/')+'/'+urlparts.join('/'); 
    return urla.href; 
    } 
5

Diese Lösung funktioniert in allen Browsern.

Es werden jedoch keine relativen URLs mit "..

+0

Dies hat einige Probleme. Zum Beispiel, Sie gehen davon aus, dass die Basis ist die gleiche wie Windows und ich glaube nicht, dass dies funktioniert, wenn ich einen URL-Parameter in URL habe. Sagen Sie '/img/profile.php? Url = https: // google.com/logo.svg'. – Teodors

6

URI.js scheint das Problem zu lösen:

URI("../foobar.html").absoluteTo("http://example.org/hello/world.html").toString() 

auch http://medialize.github.io/URI.js/docs.html#absoluteto

Nicht testeed mit IE6, aber vielleicht hilfreich anderen für das allgemeine Problem zu suchen.

+1

Auf der Knotenseite (zum Crawlen, usw.) ist die korrekte Bibliothek hier über 'npm install URIjs' verfügbar, nicht die andere Bibliothek mit ähnlichem Namen – y3sh

+0

das npm-Paket wurde in' urijs' geändert https: // github .com/medialize/URI.js # using-urijs –

8

Ich fand auf diesem blog eine andere Methode, die wirklich wie @bobince-Lösung aussieht.

function canonicalize(url) { 
    var div = document.createElement('div'); 
    div.innerHTML = "<a></a>"; 
    div.firstChild.href = url; // Ensures that the href is properly escaped 
    div.innerHTML = div.innerHTML; // Run the current innerHTML back through the parser 
    return div.firstChild.href; 
} 

Ich fand es ein wenig eleganter, keine große Sache.

12

Sie können es auf IE6 nur das Klonen das Element funktioniert:

function qualifyURL(url) { 
    var a = document.createElement('a'); 
    a.href = url; 
    return a.cloneNode(false).href; 
} 

(Getestet mit IETester auf IE6 und IE5.5 Modi)

+0

Beste Antwort IMO. So sauber, danke! –

3

Dies ist die Funktion, die ich Grund lösen verwenden relative URLs:

function resolveRelative(path, base) { 
    // Absolute URL 
    if (path.match(/^[a-z]*:\/\//)) { 
     return path; 
    } 
    // Protocol relative URL 
    if (path.indexOf("//") === 0) { 
     return base.replace(/\/\/.*/, path) 
    } 
    // Upper directory 
    if (path.indexOf("../") === 0) { 
     return resolveRelative(path.slice(3), base.replace(/\/[^\/]*$/, '')); 
    } 
    // Relative to the root 
    if (path.indexOf('/') === 0) { 
     var match = base.match(/(\w*:\/\/)?[^\/]*\//) || [base]; 
     return match[0] + path.slice(1); 
    } 
    //relative to the current directory 
    return base.replace(/\/[^\/]*$/, "") + '/' + path.replace(/^\.\//, ''); 
} 

-Test auf jsfiddle: https://jsfiddle.net/n11rg255/

Es funktioniert sowohl im Browser als auch in node.js oder anderen Umgebungen.

6

Ich wollte eigentlich eine Annäherung an diese, die keine Änderung des Originaldokuments (nicht einmal vorübergehend) erfordert, aber immer noch die eingebaute URL-Analyse des Browsers und so. Außerdem wollte ich meine eigene Basis zur Verfügung stellen können (wie Ecmanaught's Antwort). Es ist ziemlich einfach, aber nutzt createHTMLDocument (könnte mit create ersetzt werden ein bisschen mehr kompatibel möglicherweise sein):

function absolutize(base, url) { 
    d = document.implementation.createHTMLDocument(); 
    b = d.createElement('base'); 
    d.head.appendChild(b); 
    a = d.createElement('a'); 
    d.body.appendChild(a); 
    b.href = base; 
    a.href = url; 
    return a.href; 
} 

http://jsfiddle.net/5u6j403k/

+1

Nicht sicher, ob ich etwas vermisse, aber IE6 (noch 7, 8) unterstützt nicht "document.implementation.createHTMLDocument" – Oriol

+0

Ich benutzte dies, wenn ich eine Webanwendung zum Laden und Scrape anderer Seiten verwendete. Beim Aufruf von jQuery.load, $ ("# loadedHere"). CreateElement ("a"). Url = "foo" ' führte zu einer leeren URL, so dass ich auf ein separates Dokument zurückgreifen musste. – ericP