从相对的网址获取绝对网址。(IE6问题)


80

我目前正在使用以下功能将相对网址“转换”为绝对网址:

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 +一吨其他潜在变量确实使它陷入困境!

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


1
您可以使用js-uri将相对URI解析为绝对的URI。
Gumbo

谢谢Gumbo,我想这是必须要做的。我本来希望有一个更简洁的解决方案,但是无论如何,还是谢谢您,我不知道这个js-uri类存在!
詹姆斯

8
真是可笑!不在乎IE6。节省了我几个小时。你摇滚
汤姆·哈里森

我没有使用它,我只有“ foo”,我想要“ example.com/foo
Jaime Hablutzel 2012年

js-uri库似乎没有按照原始海报的要求执行。
djsmith

Answers:


47

多么奇怪!但是,当您使用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;
}

有点丑陋,但比自己动手更简洁。


我在不需要代码进行转义的博客上找到了类似的解决方案:stackoverflow.com/a/22918332/82609
Sebastien Lorber 2014年

根据HTML规范,此方法用 (U + FFFD)替换null(U + 0000)。
Oriol 2016年

26

只要浏览器正确实现<base>标记,浏览器就倾向于:

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/


晚会已经晚了三年,因此要想走上高峰就需要一段时间,而没有行销人员或很多人都想解决这个问题,并且想要一个代码保守和准确的解决方案。
ecmanaut

2
除了支持任意基本URL,这与问题中提出的解决方案有何不同?可以在IE 6上使用吗?
约翰

1
@AmadeusDrZaius不应该,但如果您愿意,可以这样。JavaScript只会在行尾添加自动分号,否则不会使下一行成为无效语句。“,foo = 1”是语法错误,因此整个var语句将在不加分号的情况下进行批量评估。
ecmanaut

2
@AndreasDietrich那是因为您没有将任何参数传递给该base_url参数,因此它变为undefined并且被字符串化为"undefined"。您应该改为传递空字符串。或者,如果要将第二个参数设为可选,请使用our_base.href = base_url || ""代替our_base.href = base_url..
Oriol

1
好主意,@ Oriol –对于没有同时传递两个参数的用户,没有理由不使用更友好的默认行为。集成。
ecmanaut

16

您只需克隆元素即可使其在IE6上工作:

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

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


10

我在此博客上发现了另一种看起来像@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;
}

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


7

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

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

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

没有经过IE6认证,但是对于其他搜索一般问题的人可能有所帮助。


1
在事物的节点方面(用于抓取等),此处提供了正确的库npm install URIjs,而不是通过其他名称相似的库提供
y3sh 2015年

名为npm的软件包已更改为urijs github.com/medialize/URI.js#using-urijs
Daniel Lizik 2016年

7

我实际上想要一种不需要修改原始文档的方法(甚至不是临时的),但是仍然使用浏览器的内置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/


1
不知道我是否丢失了某些内容,但是IE6(或document.implementation.createHTMLDocument
更高版本

我在使用Web应用程序加载和抓取其他页面时使用了此功能。在jQuery.load的回调中,$("#loadedHere").createElement("a").url="foo"URL为空,因此我不得不求助于创建单独的文档。
ericP '17

5

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

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

3

这是我用来解析基本相对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或其他环境中运行。



0

如果url不是以“ /”开头

取当前页面的URL,截去最后一个“ /”之后的所有内容;然后附加相对网址。

否则,如果url以'/'开头

取当前页面的URL,并截去单个'/'右边的所有内容;然后附加网址。

否则url以#或?开头

取得当前页面的网址,然后简单地追加 url


希望对你有帮助


2
您忘记了URL可以以“ //”开头,这使它们成为相对于方案的。//foo.com/bar/
斯科特·

1
您还忘记了点分相对的../../语法(是否忽略是否重要取决于输出所需要的内容)
hallvors

-1

如果它在浏览器中运行,那么这种方法对我来说是有效的。

  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;
  }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.