从相对 URL 获取绝对 URL。 (IE6问题)

Posted

技术标签:

【中文标题】从相对 URL 获取绝对 URL。 (IE6问题)【英文标题】:Getting an absolute URL from a relative one. (IE6 issue) 【发布时间】:2010-10-03 00:27:31 【问题描述】:

我目前正在使用以下函数将相对 URL“转换”为绝对 URL:

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

这在大多数浏览器中运行良好,但 IE6 仍然坚持返回相对 URL!如果我使用 getAttribute('href'),它会做同样的事情。

我能够从 IE6 中获取合格 URL 的唯一方法是创建一个 img 元素并查询它的 'src' 属性——这样做的问题是它会生成一个服务器请求;我想避免的事情。

所以我的问题是:有什么方法可以在 IE6 中从相对的 URL 中获取完全限定的 URL(无需服务器请求)?


在你推荐一个快速的正则表达式/字符串修复之前,我向你保证它并不是那么简单。基本元素 + 双周期相对 url + 大量其他潜在变量真的很糟糕!

必须有一种方法可以做到这一点,而不必创建庞大的正则表达式解决方案??

【问题讨论】:

您可以使用js-uri 将相对URI 解析为绝对URI。 谢谢Gumbo,我想这是必须的。我希望有一个更简洁的解决方案,但无论如何谢谢你,我从来不知道这个 js-uri 类存在! 甜蜜的黑客!不关心IE6。节省了我几个小时。你摇滚。 我没有得到它,我只有“foo”,我想要“example.com/foo” js-uri 库似乎并没有做到原发帖人想要的。 【参考方案1】:

多么奇怪!但是,当您使用 innerhtml 而不是 DOM 方法时,IE 确实可以理解它。

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;

有点难看,但比 Doing It Yourself 更简洁。

【讨论】:

我在一个不需要代码转义的博客上找到了类似的解决方案:***.com/a/22918332/82609 这种方法将 null (U+0000) 替换为 � (U+FFFD),根据 HTML spec。【参考方案2】:

只要浏览器正确实现标签,哪些浏览器倾向于:

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;

这是一个 jsfiddle,您可以在其中进行试验:http://jsfiddle.net/ecmanaut/RHdnZ/

【讨论】:

派对迟到了三年,所以在没有营销人员或很多人遇到问题并想要代码保守且准确的解决方案的情况下,要升到顶峰需要一段时间。 除了支持任意基本 URL,这与问题中提出的解决方案有何不同?它适用于 IE 6 吗? @AmadeusDrZaius 不应该,但如果你愿意,他们可以。 javascript 仅在行尾添加自动分号时不会使下一行成为无效语句。 ", foo = 1" 是一个语法错误,因此整个 var 语句被批量计算,没有分号插入。 @AndreasDietrich 那是因为您没有将任何参数传递给base_url 参数,所以它变为undefined 并被字符串化为"undefined"。您应该改为传递空字符串。或者,如果您想让第二个参数可选,请使用 our_base.href = base_url || "" 而不是 our_base.href = base_url.. 好主意,@Oriol - 没有理由不为不传递两个参数的人提供更友好的默认行为。集成。【参考方案3】:

您只需克隆元素即可使其在 IE6 上运行:

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

(在 IE6 和 IE5.5 模式下使用 IETester 测试)

【讨论】:

【参考方案4】:

我在这个blog 上发现了另一种看起来很像@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;

我发现它更优雅一点,没什么大不了的。

【讨论】:

【参考方案5】:

URI.js 似乎解决了这个问题:

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

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

未使用 IE6 测试,但可能有助于其他搜索一般问题的人。

【讨论】:

在事物的节点方面(用于抓取等),此处正确的库可通过npm install URIjs 获得,而不是其他类似名称的库 npm 包名已更改为urijsgithub.com/medialize/URI.js#using-urijs【参考方案6】:

我实际上想要一种不需要修改原始文档(甚至暂时不需要)但仍然使用浏览器的内置 url 解析等的方法。此外,我希望能够提供自己的基础(如 ecmanaught 的回答)。它相当简单,但使用 createHTMLDocument (可以替换为 createDocument 可能更兼容):

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/

【讨论】:

不确定我是否遗漏了什么,但 IE6(也不是 7、8)不支持 document.implementation.createHTMLDocument 我在使用网络应用程序加载和抓取其他页面时使用了它。在来自 jQuery.load 的回调中,$("#loadedHere").createElement("a").url="foo" 导致了一个空 url,所以我不得不求助于创建一个单独的文档。【参考方案7】:

此解决方案适用于所有浏览器。

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

但是,它不支持其中包含“..”的相对 URL,例如“../file.png”。

【讨论】:

这有一些问题。例如,您假设 base 与 windows 相同,如果我在 url 中有一个 url 参数,我认为这不起作用。说/img/profile.php?url=https://google.com/logo.svg【参考方案8】:

这是我用来解析基本相对 URL 的函数:

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

在 jsfiddle 上测试:https://jsfiddle.net/n11rg255/

它可以在浏览器和 node.js 或其他环境中使用。

【讨论】:

【参考方案9】:

我发现这篇博客文章建议使用图像元素而不是锚点:

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

这可以可靠地扩展 URL,即使在 IE6 中也是如此。但问题是,我测试过的浏览器会在设置 image src 属性后立即下载资源——即使您在下一行将 src 设置为 null。

我将尝试使用 bobince 的解决方案。

【讨论】:

【参考方案10】:

如果url 不以'/'开头

取当前页面的url,去掉最后一个'/'之后的所有内容;然后附加相对网址。

否则如果url 以'/'开头

获取当前页面的 url 并砍掉单个“/”右侧的所有内容;然后附加网址。

如果 url 以 # 或 ? 开头,则不然

获取当前页面的 url 并简单地附加 url


希望对你有用

【讨论】:

您忘记了 URL 可以以“//”开头,这使它们与方案相关。 //foo.com/bar/ 您也忘记了带点的相对 ../../ 语法(这个省略是否重要取决于输出的要求)【参考方案11】:

如果它在浏览器中运行,这对我有用..

  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;
  

【讨论】:

以上是关于从相对 URL 获取绝对 URL。 (IE6问题)的主要内容,如果未能解决你的问题,请参考以下文章

Java - 如果我知道域,如何将相对 URL 字符串更改为绝对 URL?

在 Java 中从相对 URL 构建绝对 URL

jquery 获取URL相对/绝对路径问题

相对表单操作解析为绝对 URL?

来自 C# 中的基本 URL + 相对 URL 的绝对 URL

从 Freemarker 中的相对链接获取绝对链接