11

我需要生成href一个 URI。除了需要百分比编码的保留字符之外,一切都很容易,例如链接/some/path;element应该显示为<a href="/some/path%3Belement">(我知道它path;element代表单个实体)。

最初我正在寻找一个可以执行此操作的 Java 库,但我最终自己编写了一些东西(请看下面的 Java 失败的原因,因为这个问题不是 Java 特定的)。

因此,RFC 3986确实建议何时不编码。当我读到它时,当角色属于unreserved (ALPHA / DIGIT / "-" / "." / "_" / "~")班级时,这应该发生。到现在为止还挺好。但是相反的情况呢?RFC 只提到百分比 ( %) 总是需要编码。但是其他人呢?

问题:假设所有非保留的内容都可以/应该进行百分比编码是否正确?例如,左括号(不一定需要编码,但分号需要;。如果我不对其进行编码,我最终会在关注时寻找/first* <a href="/first;second">。但是,正如预期的那样,<a href="/first(second">我总是最终会寻找。/first(second让我感到困惑的是,就 RFC 而言,两者(;属于同一sub-delims类。正如我想象的那样,对所有非保留的内容进行编码是一个安全的选择,但是对于本地化 URI 而言,SEOability 和用户友好性又如何呢?

现在,Java 库失败了。我试过这样做,
new java.net.URI("http", "site", "/pa;th", null).toASCIISTring()
但这http://site/pa;th并不好。观察到类似的结果:

  • javax.ws.rs.core.UriBuilder
  • Spring的UriUtils - 我已经尝试encodePath(String, String)encodePathSegment(String, String)

[*]是点击时在服务器端/first调用的结果HttpServletRequest.getServletPath()<a href="/first;second">

编辑:我可能需要提到这种行为是在 Tomcat 下观察到的,并且我检查了 Tomcat 6 和 7 的行为方式相同。

4

2 回答 2

5

假设所有非保留的东西都可以/应该进行百分比编码是否正确?

不,RFC 3986 是这样说的:

“在正常情况下,URI 中的八位字节被百分比编码的唯一时间是在从其组成部分生成 URI 的过程中。这是当实现确定哪些保留字符将用作子组件分隔符以及哪些可以安全地用作数据。”

这意味着您决定需要根据上下文对<delimiter>哪些分隔符(即字符)进行编码。那些不需要编码的不应该编码。

例如,/如果 a 出现在路径组件中,则不应对其进行百分比编码,但应在它出现在查询或片段中时对其进行百分比编码。

所以,事实上,一个;字符(它的成员不<reserved>应该被自动百分号编码。事实上,java URL 和 URI 类不会这样做;请参阅URI(...) javadoc,特别是第 7 步)了解如何<path>组件被处理。

本段加强了这一点:

“保留字符的目的是提供一组定界字符,这些字符可与 URI 中的其他数据区分开来。在用相应的百分比编码八位字节替换保留字符方面不同的 URI 是不等价的。百分比编码保留字符,或解码与保留字符相对应的百分比编码八位字节,将改变大多数应用程序解释 URI 的方式。因此,保留集中的字符受到规范化保护,因此可以安全地用于特定于方案和用于在 URI 中分隔数据子组件的特定于生产者的算法。”

所以这表示包含百分比编码;的 URL 与包含 raw 的 URL 不同;。最后一句话暗示它们不应该被自动编码或解码。


这给我们留下了一个问题——为什么 ;进行百分比编码?

假设您有一个 CMS,人们可以在其中创建具有任意路径的任意页面。稍后,我需要生成指向所有页面的 href 链接,例如站点地图组件。因此,我需要一种算法来知道要转义哪些字符。在这种情况下,分号必须按字面意思处理,并且应该被转义。

抱歉,但这并不意味着应该转义分号。

就 URL / URI 规范而言,;没有特殊含义。它可能对特定的网络服务器/网站有特殊的意义,但一般来说(即没有特定的网站知识)你无法知道这一点。

  • 如果;在特定的 URI 中确实具有特殊含义,那么如果您对它进行百分比转义,那么您就破坏了该含义。例如,如果站点使用;允许将会话令牌附加到路径,那么百分比编码将阻止它识别会话令牌......

  • 如果;只是某个客户端提供的数据字符,那么如果您对其进行百分比编码,则可能会更改 URI 的含义。这是否重要取决于服务器的工作;即是否解码作为应用程序逻辑的一部分。

这意味着知道“正确的事情”需要深入了解 URI 对最终用户和/或站点的意义。这需要先进的读心技术来实施。我的建议是让 CMS 通过适当地转义 URI 路径的任何分隔符来解决它,然后再将它们传递给您的软件。该算法必须特定于 CMS 和内容交付平台。它/他们将响应对由 URL 标识的文档的请求,并且需要知道如何解释它们。

(支持使用任意路径的任意人有点疯狂。必须有一些限制。例如,甚至 Windows 都不允许您在文件名组件中使用文件分隔符。所以您将不得不在某处有一些界限。它只是决定它们应该在哪里。)

于 2011-05-16T13:10:53.703 回答
2

绝对路径部分的ABNF :

 path-absolute = "/" [ segment-nz *( "/" segment ) ]
 segment       = *pchar
 segment-nz    = 1*pchar
 pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
 pct-encoded   = "%" HEXDIG HEXDIG
 unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
 reserved      = gen-delims / sub-delims
 sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
               / "*" / "+" / "," / ";" / "="

pchar包括子分隔符,因此您不必在路径部分中对任何这些进行编码::@-._~!$&'()*+,;=

我编写了自己的 URL 构建器,其中包括路径编码器 - 一如既往,警告购买者。

于 2011-05-06T16:12:49.340 回答