我们的一些用户要求我们在我们发送给他们的请求的 HTTP 标头中包含与他们的帐户相关的数据,甚至是他们从我们的 API 获得的响应。在命名、格式...等方面,添加自定义 HTTP 标头的一般约定是什么?
此外,请随时发布您在网络上偶然发现的任何智能用法;我们正在尝试使用最好的目标来实现这一点:)
的建议是 以“X-”开头。例如X-Forwarded-For
、X-Requested-With
。 RFC 2047 的第 5 节也提到了这一点。
更新 1:2011 年 6 月,发布了第一个 IETF draft,以弃用对非标准标头使用“X-”前缀的建议。原因是当以“X-”为前缀的非标准标头成为标准时,删除“X-”前缀会破坏向后兼容性,迫使应用程序协议支持这两个名称(例如,x-gzip
和 gzip
现在是等效的)。因此,官方建议将它们命名为明智,不带“X-”前缀。
更新 2:2012 年 6 月,弃用使用“X-”前缀的建议已正式成为 RFC 6648。以下是相关引用:
3. 对新参数创建者的建议......不应在其参数名称前加上“X-”或类似结构。
4. 对协议设计者的建议……不应禁止注册带有“X-”前缀或类似结构的参数。不得规定带有“X-”前缀或类似结构的参数需要被理解为非标准化的。不得规定没有“X-”前缀或类似结构的参数需要被理解为标准化。
请注意,“SHOULD NOT”(“不鼓励”)与“MUST NOT”(“forbidden”)不同,另请参阅 RFC 2119,了解有关这些关键字的另一个规范。换句话说,您可以继续使用以“X-”为前缀的标头,但它不再是官方推荐的,您可能绝对不会将它们记录为公共标准。
概括:
官方建议只是合理地命名它们,不要使用“X-”前缀
您可以继续使用以“X-”为前缀的标头,但官方不再推荐它,您可能绝对不会将它们记录为公共标准
这个问题值得重新阅读。提出的实际问题与 CSS 属性中的供应商前缀不同,在这些属性中,面向未来并考虑供应商支持和官方标准是合适的。实际提出的问题更类似于选择 URL 查询参数名称。没有人应该关心他们是什么。但是为自定义的命名间隔是完全有效的——而且是常见的、正确的——要做的事情。
基本原理:这是关于开发人员之间对自定义的、特定于应用程序的标头的约定——“与其帐户相关的数据”——这与供应商、标准机构或由第三方实施的协议无关,除了开发人员有问题的只是需要避免可能有服务器、代理或客户端其他用途的标头名称。因此,给出的“X-Gzip/Gzip”和“X-Forwarded-For/Forwarded-For”示例没有实际意义。提出的问题是关于私有 API 上下文中的约定,类似于 URL 查询参数命名约定。这是偏好和名称间距的问题;对任何没有“X”的代理或供应商支持“X-ClientDataFoo”的担忧显然是错误的。
“X-”前缀没有什么特别或神奇的地方,但它有助于明确它是一个自定义标题。事实上,RFC-6648 等人帮助支持使用“X-”前缀的情况,因为——由于 HTTP 客户端和服务器的供应商放弃了前缀——你的应用程序特定、私有 API、个人数据——传递机制正在变得更好地防止名称空间冲突与少量官方保留的标头名称。也就是说,我个人的偏好和建议是更进一步,例如“X-ACME-ClientDataFoo”(如果您的小部件公司是“ACME”)。
恕我直言,IETF 规范不足以具体回答 OP 的问题,因为它无法区分完全不同的用例:(A) 供应商一方面引入了新的全球适用功能,如“Forwarded-For”,而 (B)应用程序开发人员向/从客户端和服务器传递特定于应用程序的字符串。该规范只关注前者,(A)。这里的问题是(B)是否有约定。有。它们涉及按字母顺序将参数组合在一起,并将它们与许多标准相关的类型 (A) 标头分开。使用“X-”或“X-ACME-”前缀对于(B)来说是方便和合法的,并且与(A)不冲突。越多的供应商停止在 (A) 中使用“X-”, (B) 将变得越清晰。
示例:谷歌(在各种标准机构中占有一定的比重)——截至今天,20141102 在对我的回答进行了轻微的编辑——目前使用“X-Mod-Pagespeed”来表示他们的 Apache 模块的版本参与转换给定的响应。有没有人真的建议谷歌应该使用“Mod-Pagespeed”,没有“X-”,和/或要求 IETF 祝福它的使用?
摘要:如果您在应用程序中使用自定义 HTTP 标头(有时作为 cookie 的替代品)来向/从您的服务器传递数据,并且这些标头明确地不打算在您的上下文之外使用应用程序,使用“X-”或“X-FOO-”前缀命名它们是合理且常见的约定。
HTTP 标头的格式在 HTTP 规范中定义。我将讨论 HTTP 1.1,其规范为 RFC 2616。在第 4.2 节“消息头”中,定义了头的一般结构:
message-header = field-name ":" [ field-value ]
field-name = token
field-value = *( field-content | LWS )
field-content = <the OCTETs making up the field-value
and consisting of either *TEXT or combinations
of token, separators, and quoted-string>
这个定义基于两个主要支柱,token 和 TEXT。两者都在第 2.2 节“基本规则”中定义。令牌是:
token = 1*<any CHAR except CTLs or separators>
依次基于 CHAR、CTL 和分隔符:
CHAR = <any US-ASCII character (octets 0 - 127)>
CTL = <any US-ASCII control character
(octets 0 - 31) and DEL (127)>
separators = "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | "\" | <">
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | SP | HT
文本是:
TEXT = <any OCTET except CTLs,
but including LWS>
LWS 是线性空白,我不会复制它的定义,而 OCTET 是:
OCTET = <any 8-bit sequence of data>
定义附有注释:
The TEXT rule is only used for descriptive field contents and values
that are not intended to be interpreted by the message parser. Words
of *TEXT MAY contain characters from character sets other than ISO-
8859-1 [22] only when encoded according to the rules of RFC 2047
[14].
所以,两个结论。首先,很明显,标题名称必须由 ASCII 字符的子集组成——字母数字、一些标点符号,而不是其他很多。其次,标头值的定义中没有任何内容将其限制为 ASCII 或排除 8 位字符:它明确地由八位字节组成,只有控制字符被禁止(请注意,CR 和 LF 被视为控件)。此外,对 TEXT 产生的评论意味着八位字节将被解释为 ISO-8859-1 中的内容,并且存在一种编码机制(顺便说一句,这很可怕)用于表示该编码之外的字符。
因此,特别是为了响应@BalusC,很明显,根据规范,标头值在 ISO-8859-1 中。我已经在 Tomcat 的标头中发送了高 8859-1 字符(特别是法语中使用的一些重音元音),并让 Firefox 正确解释它们,所以在某种程度上,这在实践中和理论上都有效(虽然这是一个 Location 标头,其中包含一个 URL,并且这些字符在 URL 中是不合法的,所以这实际上是非法的,但在不同的规则下!)。
也就是说,我不会依赖 ISO-8859-1 在所有服务器、代理和客户端上工作,所以我会坚持使用 ASCII 作为防御性编程问题。
RFC6648 建议您假设您的自定义标头“可能已标准化、公开、普遍部署或可跨多个实施使用”。因此,建议不要在其前面加上“X-”或类似的结构。
但是,有一个例外“当 [您的标题] 极不可能被标准化时”。对于此类“特定于实现和私有使用”的标头,RFC 表示名称空间(例如供应商前缀)是合理的。
X-
前缀的理由,因为没有任何前缀的东西更有可能变得标准化.
X-
发生冲突,但这与 RFC6648 主要采用的假设不同。 RFC 的例外说明了未来标准标头与来自另一个供应商的标头之间的潜在冲突,该供应商的技术可能通过公司合并等与您的技术集成。这就是为什么例外需要供应商前缀。
修改,或者更准确地说,添加额外的 HTTP 标头是一个很好的代码调试工具。
当 URL 请求返回重定向或图像时,没有 html“页面”可以临时将调试代码的结果写入其中 - 至少在浏览器中不可见。
一种方法是将数据写入本地日志文件并稍后查看该文件。另一种方法是临时添加反映正在调试的数据和变量的 HTTP 标头。
我经常添加额外的 HTTP 标头,例如 X-fubar-somevar: 或 X-testing-someresult: 来测试结果——并且发现了很多原本很难追踪的错误。
if (header == "x-gzip")
编辑为if (header == "x-gzip" || header == "gzip")
就很容易。至于你的比喻,还有一个:就像军方在说“哦,把一个人从私人换成将军很麻烦。所以,从现在开始,你们都是将军。现在我们不需要这样做了很多工作”X-
前缀。我反对它,但继续做吧。对于标题OTOH,不要丢弃它。它可以很容易地查看和去,“哦,它是非标准的;我可以忽略它”与“有那些非标准的X-
标头,然后有一个我不认识的标头;我可以忽略它吗安全吗?”X-
以确保与公共标头不冲突(感谢 RFC6648,它处理公共标头),此外绝对使用任意私有前缀。对于公共标头,在任何情况下都不要使用X-
。