2009-01-22 15 views
74

Actualmente estoy usando la siguiente función para 'convertir' una URL relativa a un absoluto uno:Obteniendo una URL absoluta de una relativa. (Tema IE6)

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

Esto funciona bastante bien en la mayoría de los navegadores, pero IE6 insiste en volver la URL relativa todavía! Hace lo mismo si uso getAttribute ('href').

La única forma en que he podido obtener una URL válida de IE6 es crear un elemento img y consultar su atributo 'src'; el problema es que genera una solicitud de servidor; algo que quiero evitar

Entonces mi pregunta es: ¿hay alguna forma de obtener una URL completa en IE6 de una relativa (sin una solicitud de servidor)?


Antes de recomendar una corrección rápida de expresiones regulares/cadenas, le aseguro que no es así de simple. Elementos base + urls relativas de período doble + una tonelada de otras variables potenciales realmente lo convierten en el infierno!

Debe haber una forma de hacerlo sin tener que crear un mamut de una solución regular?

+8

corte dulce! No me importa IE6. Me ahorró horas. Tu rock –

+1

Puede usar [js-uri] (http://code.google.com/p/js-uri/) para resolver el URI relativo en uno absoluto. – Gumbo

+0

Gracias Gumbo, supongo que esto tendrá que hacer. Me hubiera gustado una solución más concisa, pero gracias de todos modos, ¡nunca supe que existía esta clase de js-uri! – James

Respuesta

0

url Si no comienza con '/'

Tome URL de la página actual, cortar todo más allá de la última '/'; luego añada la URL relativa.

url Porque si empieza con '/'

Tome URL de la página actual y cortar todo a la derecha de la única '/'; luego añada la url.

¿Si el url comienza con # o?

Take URL de la página actual y simplemente anexar url


espero que funcione para usted

+2

Olvidó que las URL pueden comenzar con "//", lo que las hace relacionadas con el esquema. //foo.com/bar/ –

+1

también olvidó la sintaxis relativa de puntos ../../ (si esta omisión importa o no depende de para qué se necesita la salida) – hallvors

46

Qué extraño! IE lo entiende, sin embargo, cuando usas innerHTML en lugar de métodos DOM.

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

Un poco feo, pero más conciso que Doing It Yourself.

+1

¡Este método funciona muy bien para mí! ¡Gracias por publicarlo! – zachleat

+0

Se confirmó que funciona en IE7. – djsmith

+0

http://jsfiddle.net/z9MQE/ –

2

me encontré con esta entrada del blog que sugiere el uso de un elemento de imagen en lugar de un ancla:

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

que trabaja para ampliar de forma fiable una URL, incluso en IE6. Pero el problema es que los navegadores que he probado descargarán inmediatamente el recurso al configurar el atributo src de la imagen, incluso si configuras el src como nulo en la siguiente línea.

Voy a darle una oportunidad a la solución de Bobince.

27

Mientras el navegador implementa la base < > etiqueta correctamente, lo que los navegadores tienden a:

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

Aquí hay una jsFiddle donde se puede experimentar con ella: http://jsfiddle.net/ecmanaut/RHdnZ/

+0

waho, la mejor respuesta de la historia. Ojalá pueda votar 10 veces. – Hartator

+0

Llegaron tres años tarde a la fiesta, por lo que tomará un tiempo llegar a la cima sin marketing o mucha gente teniendo el problema y buscando una solución precisa y conservadora de código. – ecmanaut

+0

Mejor tarde que nunca. Creo que su solución es inteligente y más sólida que la otra, confiar en el navegador parece ser la mejor forma de hacerlo. Incluso si se pudiera percibir como rey de hacky para inyectar una etiqueta base. – Hartator

0

Si se ejecuta en el navegador , este tipo de funciona para mí ..

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

Esta solución funciona en todos los navegadores.

/** 
* Given a filename for a static resource, returns the resource's absolute 
* URL. Supports file paths with or without origin/protocol. 
*/ 
function toAbsoluteURL (url) { 
    // Handle absolute URLs (with protocol-relative prefix) 
    // Example: //domain.com/file.png 
    if (url.search(/^\/\//) != -1) { 
    return window.location.protocol + url 
    } 

    // Handle absolute URLs (with explicit origin) 
    // Example: http://domain.com/file.png 
    if (url.search(/:\/\//) != -1) { 
    return url 
    } 

    // Handle absolute URLs (without explicit origin) 
    // Example: /file.png 
    if (url.search(/^\//) != -1) { 
    return window.location.origin + url 
    } 

    // Handle relative URLs 
    // Example: file.png 
    var base = window.location.href.match(/(.*\/)/)[0] 
    return base + url 

Sin embargo, no es compatible con URLs relativas ".." en ellos, como "../file.png".

+0

Esto tiene algunos problemas. Por ejemplo, supones que la base es lo mismo que Windows y no creo que esto funcione si tengo un parámetro de URL en url. Diga '/img/profile.php? Url = https: // google.com/logo.svg'. – Teodors

6

URI.js parece resolver el problema:

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

Ver también http://medialize.github.io/URI.js/docs.html#absoluteto

No testeed con IE6, pero tal vez útil para otros que buscan a la cuestión general.

+1

En el lado del nodo de cosas (para rastrear, etc.), la biblioteca correcta aquí está disponible a través de 'npm install URIjs', no la otra biblioteca con el mismo nombre – y3sh

+0

el paquete npm named ha cambiado a' urijs' https: // github .com/medialize/URI.js # using-urijs –

8

Encontré en este blog otro método que realmente se parece a la solución @bobince.

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

Me pareció un poco más elegante, no es un gran problema.

12

Puede hacer que funcione en IE6 solo la clonación del elemento:

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

(probada usando IETester sobre los modos de IE6 y IE5.5)

+0

Mejor respuesta IMO. Tan limpio, gracias! –

3

Ésta es la función que utilizo para resolver básica URL relativos:

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(/^\.\//, ''); 
} 

probarlo en jsFiddle: https://jsfiddle.net/n11rg255/

Funciona tanto en el navegador como en node.js u otros entornos.

6

Realmente quería un enfoque para esto que no requiriera modificar el documento original (ni siquiera temporalmente) pero aún así usar el análisis url incorporado del navegador y tal. Además, quería poder proporcionar mi propia base (como la respuesta de ecmanaught). Es bastante sencillo, pero utiliza createHTMLDocument (podría ser reemplazado por createDocument a ser un poco más compatible posiblemente):

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

No estoy seguro de si me falta algo, pero IE6 (ni 7, 8) no es compatible con 'document.implementation.createHTMLDocument' – Oriol

+0

Lo usé cuando estaba usando una aplicación web para cargar y raspar otras páginas. En la devolución de llamada de jQuery.load, '$ (" # loadedHere "). CreateElement (" a "). Url =" foo "' resultó en una url vacía, así que tuve que recurrir a la creación de un documento separado. – ericP

Cuestiones relacionadas