【问题标题】:Why is "&reg" being rendered as "®" without the bounding semicolon为什么“&reg”被呈现为“®”而没有分界符
【发布时间】:2013-03-20 18:51:19
【问题描述】:

我遇到了一个问题,该问题是通过我们的 Google 广告词驱动的营销活动揭示的。使用的标准参数之一是“区域”。当用户搜索并点击赞助链接时,Google 会生成一个长 URL 来跟踪点击,并在引荐来源网址中发送一堆内容。我们将其捕获为我们的记录,并且我们注意到“区域”参数不正确。应该是什么

http://ravercats.com/meow?foo=bar&region=catnip

改为:

http://ravercats.com/meow?foo=bar®ion=catnip

我已验证所有浏览器都会出现这种情况。据我了解HTML entity syntax的定义如下:

&VALUE;

其中前导边界是与号,结束边界是分号。看起来很简单。问题是 ® 实体没有尊重这一点,它在我们的系统中造成了各种破坏。

有人知道为什么会这样吗?它是 DTD 中的错误吗? (我正在寻找当前的 HTML DTD,看看我是否能理解它)我试图找出跨浏览器的共同点来实现这一点,因此我正在寻找 DTD。

这是您可以使用的证明。获取这段代码,用它制作一个 HTML 文件并在浏览器中呈现它:

<html>
<a href="http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct">http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct</a>
</html>

编辑:对于建议我需要转义整个 URL 的每个人,上面的示例 URL 就是这样,示例。真正的 URL 直接来自 Google,我无法控制它的构造方式。这些建议虽然有效,但并未回答以下问题:“为什么会发生这种情况”。

【问题讨论】:

  • 也许尝试将您的 & 替换为 &amp;amp; 或 URL 编码的 & 符号 %26
  • 您未转义的&amp; 首先在 HTML 中是非法的。在那之后尝试对宽松的浏览器进行语言律师有点愚蠢。 (顺便说一句,这在 Firefox 中运行良好;这是 2005 年修复的错误。)
  • 这些是示例 URL。实际的 URL 直接来自 Google,所以我无法控制它。我很欣赏这些建议,但它没有回答为什么会发生这种情况的问题,特别是针对“reg”实体而不是其他实体。
  • 网址来自谷歌还是包含该网址的html是? & 在 url 中非常好,但需要在 html 中编码。

标签: html query-string


【解决方案1】:

虽然有效的字符引用总是以分号结尾,但出于向后兼容的原因,一些不带分号的无效命名字符引用被现代浏览器的 HTML 解析器识别。

要么你知道整个列表是什么,要么你遵循 HTML5 规则,当&amp;amp; 有效时没有被转义(例如,当后面跟着一个空格),或者在有疑问时总是将&amp;amp; 转义为&amp;amp; .

作为参考,不带分号的命名字符引用的完整列表是:

AElig、AMP、Aacute、Acirc、Agrave、Aring、Atilde、Auml、COPY、Ccedil、 ETH,Eacute,Ecirc,Egrave,Euml,GT,Iacute,Icirc,Igrave,Iuml,LT, Ntilde、Oacute、Ocirc、Ograve、Oslash、Otilde、Ouml、QUOT、REG、THORN、 Uacute,Ucirc,Ugrave,Uuml,Yacute,aacute,acirc,急性,aelig, agrave,amp,aring,atilde,auml,brvbar,ccedil,cedil,cent,复制, 当前,deg,divide,eacute,ecirc,egrave,eth,euml,frac12,frac14, frac34, gt, iacute, icirc, iexcl, igrave, iquest, iuml, laquo, lt, macr, micro, middot, nbsp, not, ntilde, oacute, ocirc, ograve, ordf, ordm, oslash, otilde, ouml, para, plusmn, 磅, quot, raquo, reg, 教派,害羞,sup1,sup2,sup3,szlig,刺,时代,uacute,ucirc, ugrave, uml, uuml, yacute, 日元, yuml

但是,应该注意的是,只有在属性值中,如果下一个字符是= 或字母数字 ASCII 字符,则上述列表中的命名字符引用不会被符合 HTML5 解析器的处理。

有关带或不带结束分号的命名字符引用的完整列表,请参阅here

【讨论】:

  • 我不知道有任何实体可以在没有分号的情况下“逃脱”。感谢您回答问题并为我提供良好的参考。
  • 我遇到了一个有趣的案例,URL 中的&amp;provider=XXX&amp;reg=1 被一些过时或不常见的浏览器替换为provider=XXX®=1,完全破坏了脚本。
【解决方案2】:

这是一个非常混乱的业务,并且取决于上下文(文本内容与属性值)。

正式地,根据直到并包括 HTML 4.01 的 HTML 规范,如果下一个字符不是名称字符,实体引用可能会出现不带分号的结尾。所以例如&amp;region= 在语法上是正确的但未定义,因为实体 region 尚未定义。 XHTML 要求尾随分号。

不过,浏览器传统上遵循其他规则。由于查询 URL 的通用语法,它们解析例如href="http://ravercats.com/meow?foo=bar&amp;region=catnip" 以便 &amp;region 不被视为实体引用,而只是文本数据。作者大多使用这样的结构,尽管它们在形式上是不正确的。

与问题似乎在说什么相反,href="http://ravercats.com/meow?foo=bar&amp;region=catnip" 实际上效果很好。当字符串不在属性值中而是在文本内容中时会出现问题,这种情况相当罕见:我们通常不会在文本中编写 URL。在文本中,&amp;region= 被处理,以便&amp;reg 被识别为实体引用(对于“®”),其余的只是字符数据。这种奇怪的行为正在 HTML5 CR 中正式发布,其中条款 8.2.4.69 Tokenizing character references 描述了“双重标准”:

如果字符引用作为属性的一部分被使用, 并且匹配的最后一个字符不是“;” (U+003B) 字符,和 下一个字符是“=” (U+003D) 字符或在范围内 ASCII 数字、大写 ASCII 字母或小写 ASCII 字母, 然后,由于历史原因,所有匹配的字符 在 U+0026 与字符 (&) 之后必须不使用,并且 什么都没有返回。

因此,在属性值中,即使&amp;reg= 也不会被视为包含字符引用,更不用说&amp;region=。 (但reg_test= 是不同的情况,由于下划线字符。)

文本内容中,适用其他规则。构造 &amp;region= 会导致解析错误(根据 HTML5 CR 规则),但具有明确定义的错误处理:&amp;reg 被识别为字符引用。

【讨论】:

  • 有趣的是,在现实世界的情况下,我基本上是从 Google 收集 HTTP_REFERER 并将其解析为 cookie。我收到的 URL 已经以这种方式解析。感谢您对来源做出如此简洁的解释。
【解决方案3】:

也许尝试将您的&amp;amp; 替换为&amp;amp;?和号也是必须在 HTML 中转义的字符,因为它们被保留用作实体的一部分。

【讨论】:

    【解决方案4】:

    1:首先下面的标记是无效的(使用W3C Markup Validation Service来验证):

    <a href="http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct"></a>
    

    在上面的示例中,&amp;amp; 字符应编码为&amp;amp;,如下所示:

    <a href="http://foo.com/bar?foo=bar&amp;region=US&amp;register=lowpass&amp;reg_test=fail&amp;trademark=correct"></a>
    

    2:浏览器是宽容的;他们试图从破碎的 HTML 中找出意义。在您的情况下,所有可能有效的 HTML 实体都将转换为 HTML 实体。

    【讨论】:

      【解决方案5】:

      这是一个简单的解决方案,它可能不适用于所有情况。

      因此:

      http://ravercats.com/meow?status=Online&amp;region=Atlantis

      致此:

      http://ravercats.com/meow?region=Atlantis&amp;status=Online

      因为我们知道&amp;reg会触发特殊字符®

      警告:如果您无法控制 URL 查询字符串参数的顺序,则必须将变量名称更改为其他名称。

      【讨论】:

        【解决方案6】:

        转义你的输出!

        很简单,您需要将 url 格式编码为 html 格式以便准确表示(理想情况下,您可以使用模板引擎变量转义函数来实现,但除此之外,在 php 中使用 htmlspecialchars($url)htmlentities($url))。

        查看您的测试用例,然后在此 jsfiddle 中查看正确编码的 html: http://jsfiddle.net/tchalvakspam/Fp3W6/

        此处为非活动代码:

        <div>
        Unescaped:
        <br>
        <a href="">http://foo.com/bar?foo=bar&region=US&register=lowpass&reg_test=fail&trademark=correct</a>
        </div>
        
        <div>
        Correctly escaped:
        <br>
        http://foo.com/bar?foo=bar&amp;region=US&amp;register=lowpass&amp;reg_test=fail&amp;trademark=correct
        </div>
        

        【讨论】:

          【解决方案7】:

          在我看来,您从 google 收到的不是实际的 URL,而是引用 url(查询字符串)的变量。所以,这就是为什么它在渲染时被解析为注册标记。

          我会说,您应该对它进行 url 编码并在处理它时对其进行解码。像任何其他包含特殊实体的变量一样。

          【讨论】:

            【解决方案8】:

            为防止这种情况发生,您应该使用encode urls,它会在 url 中用 % 和后面的十六进制数字替换像与号这样的字符。

            【讨论】:

            • 错了,完全错了。 &amp; 使用查询字符串分隔符时不应进行 URL 编码。
            猜你喜欢
            • 2017-05-08
            • 2015-11-01
            • 2014-03-09
            • 2015-03-12
            • 2013-12-31
            • 2012-08-04
            • 2021-12-05
            • 2015-04-26
            • 1970-01-01
            相关资源
            最近更新 更多