为什么“®”在没有边界分号的情况下呈现为“®”

时间:2013-03-20 18:51:19

标签: html query-string

我遇到了一个问题,这个问题是通过Google adwords推动的营销广告宣传的。使用的标准参数之一是“区域”。当用户搜索并点击赞助商链接时,Google会生成一个长URL来跟踪点击,并在引荐来源中发送大量内容。我们捕获了这些记录,我们注意到“Region”参数输入错误。应该是什么

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>

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

8 个答案:

答案 0 :(得分:38)

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

要么您知道整个列表是什么,要么您遵循HTML5规则,以确定&何时有效而不会被转义(例如,当后跟空格时)或者总是逃避&只要有疑问就&amp;

作为参考,没有分号识别的命名字符引用的完整列表是:

AElig,AMP,Aacute,Acirc,Agrave,Aring,Atilde,Auml,COPY,Ccedil,ETH,Eacute,Ecirc,Egrave,Euml,GT,Iacirc,Icirc,Igrave,Iuml,LT,Ntilde,Oacute,Ocirc ,Ograve,Oslash,Otilde,Ouml,QUOT,REG,THORN,Uacute,Ucirc,Ugrave,Uuml,Yacute,aacute,acirc,acute,aelig,agrave,amp,aring,atilde,auml,brvbar,ccedil,cedil,cent ,副本,电流,度,划分,eacute,ecirc,egrave,eth,euml,frac12,frac14,frac34,gt,iacute,icirc,iexcl,igrave,iquest,iuml,laquo,lt,macr,微,middot,nbsp ,不,ntilde,oacute,ocirc,ograve,ordf,ordm,oslash,otilde,ouml,para,plusmn,pound,quot,raquo,reg,sect,shy,sup1,sup2,sup3,szlig,thorn,times,uacute ,ucirc,ugrave,uml,uuml,yacute,yen,yuml

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

full list of named character references with or without ending semicolons, see here

答案 1 :(得分:11)

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

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

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

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

  

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

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

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

答案 2 :(得分:9)

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

答案 3 :(得分: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;,如下所示:

<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实体。

答案 4 :(得分:1)

逃避你的输出!

简单来说,您需要将url格式编码为html格式以便准确表示(理想情况下,您可以使用模板引擎变量转义函数执行此操作,但禁止使用htmlspecialchars($url)htmlentities($url) PHP)。

在这个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>

答案 5 :(得分:1)

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

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

答案 6 :(得分:1)

这是一个简单的解决方案,它可能无法在所有情况下使用。

所以:

&reg

至此:

®

因为我们知道{{1}}会触发特殊字符{{1}}

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

答案 7 :(得分:-3)

为了防止这种情况发生,你应该encode urls,它会在网址中用%和十六进制数替换字符,例如&符号。