如果<base href ...>设置为双斜杠会发生什么?

mgu*_*utt 6 html html-head

我想了解如何<base href="" />为我的网络爬虫使用一个值,所以我测试了几个主要浏览器的组合,最后发现了一些我不明白的双斜线.

如果您不喜欢阅读所有内容,请跳转到DE的测试结果.所有测试的演示:http:
//gutt.it/basehref.php

我的测试结果一步一步调用http://example.com/images.html:

A - 多个基数href

<html>
<head>
<base target="_blank" />
<base href="http://example.com/images/" />
<base href="http://example.com/" />
</head>
<body>
<img src="/images/image.jpg">
<img src="image.jpg">
<img src="./image.jpg">
<img src="images/image.jpg"> not found
<img src="/image.jpg"> not found
<img src="../image.jpg"> not found
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

结论

  • 只有第一个<base>href计数
  • /目标根开始的源
  • ../ 去一个文件夹

B - 没有斜线

<html>
<head>
<base href="http://example.com/images" />
</head>
<body>
<img src="/images/image.jpg">
<img src="image.jpg"> not found
<img src="./image.jpg"> not found
<img src="images/image.jpg">
<img src="/image.jpg"> not found
<img src="../image.jpg"> not found
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

结论

  • <base href>忽略一切的最后一个斜线所以以后http://example.com/images成为http://example.com/

C - 它应该如何

<html>
<head>
<base href="http://example.com/" />
</head>
<body>
<img src="/images/image.jpg">
<img src="image.jpg"> not found
<img src="./image.jpg"> not found
<img src="images/image.jpg">
<img src="/image.jpg"> not found
<img src="../image.jpg"> not found
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

结论

  • 与预期的测试B中的结果相同

D - 双重斜线

<html>
<head>
<base href="http://example.com/images//" />
</head>
<body>
<img src="/images/image.jpg">
<img src="image.jpg">
<img src="./image.jpg">
<img src="images/image.jpg"> not found
<img src="/image.jpg"> not found
<img src="../image.jpg">
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

E - 用空格双击

<html>
<head>
<base href="http://example.com/images/ /" />
</head>
<body>
<img src="/images/image.jpg">
<img src="image.jpg"> not found
<img src="./image.jpg"> not found
<img src="images/image.jpg"> not found
<img src="/image.jpg"> not found
<img src="../image.jpg">
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

两者都不是"有效"的网址,而是我的网络抓取工具的真实结果.请解释可以找到的DE中发生的事情../image.jpg以及为什么导致空白区别?

仅为了您的兴趣:

  • <base href="http://example.com//" />测试C相同
  • <base href="http://example.com/ /" />完全不同.只有../image.jpg找到
  • <base href="a/" /> 只发现 /images/image.jpg

Ori*_*iol 5

baseHTML规范中说明了的行为:

base元素允许作者指定文档基础URL,以解决相对URL

由于在测试中所示,如果有多个basehref,该文档库URL将是第一个。

通过以下方式解析相对URL

URL解析器应用于url,以base为基础URL,以encoding为编码。

URL解析算法在URL规范中定义。

它太复杂了,无法在此处详细说明。但基本上,这是会发生什么:

  • /对于基础URL的主机,以开头的相对URL 被计算。
  • 否则,相对URL是相对于基本URL的最后目录计算的。
  • 请注意,如果基本路径不以结尾/,则最后一部分将是文件,而不是目录。
  • ./ 是当前目录
  • ../ 向上一个目录

(“ URL”中的“目录”和“文件”可能不是正确的术语)

一些例子:

  • http://example.com/images/a/./http://example.com/images/a/
  • http://example.com/images/a/../http://example.com/images/
  • http://example.com/images//./http://example.com/images//
  • http://example.com/images//../http://example.com/images/
  • http://example.com/images/./http://example.com/images/
  • http://example.com/images/../http://example.com/

请注意,在大多数情况下,//将类似于/。正如@poncha所说

除非您使用某种形式的URL重写(在这种情况下,重写规则可能会受到斜杠数量的影响),否则uri会映射到磁盘上的路径,但在(大多数?)现代操作系统(Linux / Unix, Windows),连续的多个路径分隔符没有任何特殊含义,因此/ path / to / foo和/ path // to //// foo最终将映射到同一文件。

但是,通常/ /不会成为//

您可以使用以下代码段将相对URL列表解析为绝对URL:

var bases = [
  "http://example.com/images/",
  "http://example.com/images",
  "http://example.com/",
  "http://example.com/images//",
  "http://example.com/images/ /"
];
var urls = [
  "/images/image.jpg",
  "image.jpg",
  "./image.jpg",
  "images/image.jpg",
  "/image.jpg",
  "../image.jpg"
];
function newEl(type, contents) {
  var el = document.createElement(type);
  if(!contents) return el;
  if(!(contents instanceof Array))
    contents = [contents];
  for(var i=0; i<contents.length; ++i)
    if(typeof contents[i] == 'string')
      el.appendChild(document.createTextNode(contents[i]))
    else if(typeof contents[i] == 'object') // contents[i] instanceof Node
      el.appendChild(contents[i])
  return el;
}
function emoticon(str) {
  return {
    'http://example.com/images/image.jpg': 'good',
    'http://example.com/images//image.jpg': 'neutral'
  }[str] || 'bad';
}
var base = document.createElement('base'),
    a = document.createElement('a'),
    output = document.createElement('ul'),
    head = document.getElementsByTagName('head')[0];
head.insertBefore(base, head.firstChild);
for(var i=0; i<bases.length; ++i) {
  base.href = bases[i];
  var test = newEl('li', [
    'Test ' + (i+1) + ': ',
    newEl('span', bases[i])
  ]);
  test.className = 'test';
  var testItems = newEl('ul');
  testItems.className = 'test-items';
  for(var j=0; j<urls.length; ++j) {
    a.href = urls[j];
    var absURL = a.cloneNode(false).href;
      /* Stupid old IE requires cloning
         https://stackoverflow.com/a/24437713/1529630 */
    var testItem = newEl('li', [
      newEl('span', urls[j]),
      ' ? ',
      newEl('span', absURL)
    ]);
    testItem.className = 'test-item ' + emoticon(absURL);
    testItems.appendChild(testItem);
  }
  test.appendChild(testItems);
  output.appendChild(test);
}
document.body.appendChild(output);
Run Code Online (Sandbox Code Playgroud)
span {
  background: #eef;
}
.test-items {
  display: table;
  border-spacing: .13em;
  padding-left: 1.1em;
  margin-bottom: .3em;
}
.test-item {
  display: table-row;
  position: relative;
  list-style: none;
}
.test-item > span {
  display: table-cell;
}
.test-item:before {
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  line-height: 1em;
  text-align: center;
  border-radius: 50%;
  margin-right: .4em;
  position: absolute;
  left: -1.1em;
  top: 0;
}
.good:before {
  content: ':)';
  background: #0f0;
}
.neutral:before {
  content: ':|';
  background: #ff0;
}
.bad:before {
  content: ':(';
  background: #f00;
}
Run Code Online (Sandbox Code Playgroud)

您也可以使用以下片段:

var resolveURL = (function() {
  var base = document.createElement('base'),
      a = document.createElement('a'),
      head = document.getElementsByTagName('head')[0];
  return function(url, baseurl) {
    if(base) {
      base.href = baseurl;
      head.insertBefore(base, head.firstChild);
    }
    a.href = url;
    var abs = a.cloneNode(false).href;
    /* Stupid old IE requires cloning
       https://stackoverflow.com/a/24437713/1529630 */
    if(base)
      head.removeChild(base);
    return abs;
  };
})();
var base = document.getElementById('base'),
    url = document.getElementById('url'),
    abs = document.getElementById('absolute');
base.onpropertychange = url.onpropertychange = function() {
  if (event.propertyName == "value")
    update()
};
(base.oninput = url.oninput = update)();
function update() {
  abs.value = resolveURL(url.value, base.value);
}
Run Code Online (Sandbox Code Playgroud)
label {
  display: block;
  margin: 1em 0;
}
input {
  width: 100%;
}
Run Code Online (Sandbox Code Playgroud)
<label>
  Base url:
  <input id="base" value="http://example.com/images//foo////bar/baz"
         placeholder="Enter your base url here" />
</label>
<label>
  URL to be resolved:
  <input id="url" value="./a/b/../c"
         placeholder="Enter your URL here">
</label>
<label>
  Resulting url:
  <input id="absolute" readonly>
</label>
Run Code Online (Sandbox Code Playgroud)