超链接 href 在 innerHTML 中被错误引用?

Hyperlink href incorrectly quoted in innerHTML?

举这个非常简单的例子HTML:

<html>
    <body>This is okay &amp; fine, but the encoding of <a href="http://example.com?a=1&b=2">this link</a> seems wrong.</body>
<html>

在检查 document.body.innerHTML 时(例如在浏览器的 JS 控制台中,在 JS 本身中等),这是我看到的值:

This is okay &amp; fine, but the encoding of <a href="http://example.com?a=1&amp;b=2">this link</a> seems wrong.

这种行为在不同浏览器中都是相同的,但我无法理解,这似乎是错误的。

具体来说,原始文档中的link是http://example.com?a=1&b=2,而如果innerHTML的值被视为HTML那么它link s 到 http://example.com?a=1&amp;b=2 这是不一样的(例如,如果我创建了一个新文档,它实际上有 innerHTML 作为它的内部 HTML,然后我点击了 link 然后据我所知,浏览器将被发送到一个完全不同的 URL。

(编辑#3:我错了。首先,是的,这两个 URL 是不同的;但其次,我认为错误的 innerHTML 是正确的,它正确地代表了第一个 URL,而不是第二个!请参阅下面我自己的答案的结尾。)

这与问题 innerHTML gives me & as &amp; ! 中讨论的问题不同。在我的情况下(与该问题的情况相反)原始 HTML 是正确的,在我看来好像 innerHTML 是错误的(即因为它是 HTML 不代表原来的 HTML 代表什么)。

(编辑#2:我也错了:这并没有什么不同。但我认为 &amp; 是在href,不只是在正文中。一旦你意识到这一点,你就会发现这些实际上是同一个问题。)

谁能解释一下?

(编辑#1+4:这只是在我写完我最初的问题后才想到的,但是:“&amp; 在 href 文本 [=56] 中实际上是正确的 =],并且 & 在技术上是不正确的?”正如我第一次写这些话时所说的那样,“似乎不太可能!我当然从未见过 HTML 是这样写的。”但是 'unlikely', 或不是, 是这样的, 是我不理解的主要部分!)

也相关并且很有用,谁能解释如何清楚地得到 HTML 哪个 正确表示文档 link 的目标?您绝对不能只取消编码 innerHTML 中的所有 HTML 字符引用,因为(如我使用的示例所示,也如 innerHTML gives me & as &amp; ! 中所讨论)文本 的主要 运行 应该 被编码,并且只是取消编码所有内容都会使这些错误。

我最初认为这不是 innerHTML gives me & as &amp; ! 的重复(如上所述;并且在某种程度上它仍然不是,如果它同意同样的问题适用并不那么明显或广为人知在 href 内,如在正文中)。它仍然绝对不是 的副本(有些不清楚地询问如何使用 JS 设置 innerHTML)。

想出一个可能的(但我认为 'unlikely')解释 - 我在原始问题中作为编辑输入 - 我意识到它 答案:

  • 在 href 中使用 & 表示 & 在技术上是不正确的,而 &amp; 在技术上是正确的

我最初是从这个 SO answer https://whosebug.com/a/16168585/795690 中收集到的,我认为相关的是(正如它在该答案中所说的那样)&amp; 是表示 & 在 href 中并不像 &amp; 是在 body 文本中表示 & 的正确方法那样被广泛理解。

一旦您理解了这一点,就会明白浏览器所做的是正确的,并且返回的 innerHTML 值代表 link 正确。

编辑:

@ÁlvaroGonzález 给出了更长的答案,我花了一段时间才明白他所说的一切是如何应用的,所以我想我会尝试从我开始的地方开始解释我不明白的地方,在万一它能帮助到别人呢!

如果你从 HTML 和 <a href="http://example.com/?a=1&b=1"> 开始,然后在浏览器中检查 DOM,或者查看 JS 中 href 属性的值,你会看到 "http://example.com/?a=1&b=1"无处不在。所以看起来好像什么都没有改变,也没有什么不对劲。我不明白的是,实际上浏览器已经解析了一个技术上不正确的 href(带有无效的实体)以便能够向您显示它! (是的,很多人使用这种 'broken' 格式!)

要亲身体验,请将这个更长的 HTML 示例加载到您的浏览器中:

<html>
    <body style="font-family: sans-serif">
        <p>Now & then <a href="http://example.com/?a=1&b=2">http://example.com/?a=1&b=2</a></p>
        <p>Now &amp; then <a href="http://example.com/?a=1&amp;b=2">http://example.com/?a=1&amp;b=2</a></p>
        <p>Now &amp;amp; then <a href="http://example.com/?a=1&amp;amp;b=2">http://example.com/?a=1&amp;amp;b=2</a></p>
    </body>
</html>

然后在您的 javascript 控制台中尝试 运行 此代码取自@ÁlvaroGonzález 的回答:

const paragraphs = document.querySelectorAll("p");
for (p of paragraphs) {
  console.log(p.innerHTML);
}
const links = document.querySelectorAll("a");
for (a of links) {
  console.log(a.getAttribute("href"));
}

也可以尝试单击 link 以查看它们的去向。

一旦您理解了在那里看到的所有内容,就不会再对 innerHTML 的工作方式感到惊讶了!

大多数浏览器工具不显示实际的 HTML 因为它不会有太大帮助:

  • HTML 通常在页面加载后借助 CSS 和 JavaScript.
  • 动态生成
  • HTML 经常损坏,浏览器需要修复它以生成渲染和其他内容所需的内存表示。

所以您看到的 HTML 不是实际来源,而是根据文档的当前状态动态生成的,其中当然包括所有固定应用(在您的情况下,无效 HTML 个实体)。

以下示例有望说明所有组合:

const section = document.querySelector("section");
const invalid = document.createElement("p");
invalid.innerHTML = '<a href="http://example.com/?a=1&b=2">Invalid HTML (dynamic)</a>';
const valid = document.createElement("p");
valid.innerHTML = '<a href="http://example.com/?a=1&amp;b=2">Valid HTML (dynamic)</a>';
section.appendChild(valid);
section.appendChild(invalid);
const paragraphs = document.querySelectorAll("p");
for (p of paragraphs) {
  console.log(p.innerHTML);
}
const links = document.querySelectorAll("a");
for (a of links) {
  console.log(a.getAttribute("href"));
}
<section>
  <p><a href="http://example.com/?a=1&b=2">Invalid HTML (static)</a></p>
  <p><a href="http://example.com/?a=1&amp;b=2">Valid HTML (static)</a></p>
<section>

Is &amp; actually correct within the href text, and & technically incorrect? It seems very unlikely! I've certainly never seen HTML written that way.

没有“技术上正确”这样的东西,更不用说今天 HTML 已经非常标准化了。 (嗯,是的,有两个相互竞争的标准机构,规范也在不断发展,但基础知识早就建立了。)

& 符号开始一个字符实体,&b 是一个无效的字符实体。期间.

但它有效!这是否意味着它技术上是正确的?

之所以有效,是因为浏览器明确设计用于处理完全损坏的标记,即所谓的标签汤,因为人们认为它会简化使用:

<p><strong>Hello, World!</u>
<body><br itspartytime="yeah">
  <pink>It works!!!</red>

但是 HTML 实体只是一种编码产物。这并不意味着 URL 不允许包含文字和符号,它只是意味着 - 当在 HTML 上下文中时 - 它们需要 表示 &amp; .这与在 JavaScript 字符串中键入反斜杠以转义某些引号相同:反斜杠不会成为数据的一部分。