web-dev-qa-db-fra.com

Obtenir une URL absolue à partir d'une URL relative. (Problème IE6)

J'utilise actuellement la fonction suivante pour "convertir" une URL relative en URL absolue:

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

Cela fonctionne assez bien dans la plupart des navigateurs, mais IE6 insiste pour renvoyer toujours l'URL relative! Il en va de même si j'utilise getAttribute ('href').

La seule façon dont j'ai pu obtenir une URL qualifiée à partir d'IE6 est de créer un élément img et d'interroger son attribut 'src' - le problème avec cela est qu'il génère une requête serveur; quelque chose que je veux éviter.

Ma question est donc la suivante: existe-t-il un moyen d'obtenir une URL complète dans IE6 à partir d'une URL relative (sans demande de serveur)?


Avant de recommander une correction rapide de regex/chaîne, je vous assure que ce n'est pas si simple. Éléments de base + URL relatives à double période + une tonne d'autres variables potentielles en font vraiment l'enfer!

Il doit y avoir un moyen de le faire sans avoir à créer un mammouth d'une solution regex'y ??

79
James

Comme c'est étrange! IE le comprend cependant lorsque vous utilisez innerHTML au lieu des méthodes 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 peu moche, mais plus concis que Doing It Yourself.

47
bobince

Tant que le navigateur implémente correctement la balise <base>, les navigateurs ont tendance à:

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

Voici un jsfiddle où vous pouvez l'expérimenter: http://jsfiddle.net/ecmanaut/RHdnZ/

27
ecmanaut

Vous pouvez le faire fonctionner sur IE6 en clonant simplement l'élément:

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

(Testé en utilisant IETester sur les modes IE6 et IE5.5)

16
Oriol

J'ai trouvé sur ce blog une autre méthode qui ressemble vraiment à la solution @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;
}

Je l'ai trouvé un peu plus élégant, pas un gros problème.

10
Sebastien Lorber

RI.js semble résoudre le problème:

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

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

Pas testeed avec IE6, mais peut-être utile pour ceux qui recherchent le problème général.

7
koppor

En fait, je voulais une approche qui n'ait pas nécessité de modifier le document d'origine (même pas temporairement) mais qui utilisait toujours l'analyse syntaxique des URL du navigateur, etc. De plus, je voulais pouvoir fournir ma propre base (comme la réponse d'ecmanaught). C'est assez simple, mais utilise createHTMLDocument (pourrait être remplacé par createDocument pour être un peu plus compatible éventuellement):

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/

7
Chris Hopman

Cette solution fonctionne dans tous les navigateurs.

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

Cependant, il ne prend pas en charge les URL relatives contenant "..", comme "../file.png".

5
Feross

Voici la fonction que j'utilise pour résoudre les URL relatives de base:

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

Testez-le sur jsfiddle: https://jsfiddle.net/n11rg255/

Il fonctionne à la fois dans le navigateur et dans node.js ou d'autres environnements.

3
lovasoa

J'ai trouvé ce billet de blog qui suggère d'utiliser un élément d'image au lieu d'une ancre:

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

Cela fonctionne pour développer une URL de manière fiable, même dans IE6. Mais le problème est que les navigateurs que j'ai testés téléchargeront immédiatement la ressource lors de la définition de l'attribut src image - même si vous définissez src sur null sur la ligne suivante.

Je vais plutôt essayer la solution de bobince.

2
Jesse Hallett

Si url ne commence pas par '/'

Prenez l'url de la page actuelle, coupez tout ce qui est passé le dernier '/'; puis ajoutez l'url relative.

Sinon si url commence par '/'

Prenez l'url de la page actuelle et coupez tout à droite du single '/'; puis ajoutez l'url.

Sinon si url commence par # ou?

Prenez l'url de la page actuelle et ajoutez simplement url


J'espère que ça marche pour toi

0
geowa4