不透明 URI 中是否允许查询参数?

Are query parameters allowed in opaque URIs?

Java 的 URI class 定义不透明 URI 如下(强调我的)。

A URI is opaque if, and only if, it is absolute and its scheme-specific part does not begin with a slash character ('/'). An opaque URI has a scheme, a scheme-specific part, and possibly a fragment; all other components are undefined.

与文档一致,查询参数的不透明 URI returns null

URI uri = URI.create("Whosebug:foo?key=value#frag");
uri.isOpaque() == true
uri.getScheme() == Whosebug
uri.getSchemeSpecificPart() == foo?key=value
uri.getQuery() == null
uri.getFragment() == frag

此行为是否特定于 Java 的 URI 实现,或者 URI 规范是否不允许不透明 URI 中的查询参数?

Java的URIclass是documented as conforming to RFC 2396 and RFC 2732:

Aside from some minor deviations noted below, an instance of this class represents a URI reference as defined by RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax, amended by RFC 2732: Format for Literal IPv6 Addresses in URLs.

第 3 节 URI 句法组件 没有明确 disallow opaque 中的查询组件URI,而只是 没有为它们定义 语法。根据定义,不透明的 URI 需要特定于方案的知识才能知道 if 是否存在类似于查询组件的东西以及 how 来解析它。拥有一个是完全合法的,但如果没有这种特殊知识,就不能在一般意义上(根据此 RFC)支持它。相关的 RFC 文本是:

The URI syntax is dependent upon the scheme. In general, absolute URI are written as follows:

<scheme>:<scheme-specific-part>

An absolute URI contains the name of the scheme being used (<scheme>) followed by a colon (":") and then a string (the <scheme-specific-part>) whose interpretation depends on the scheme.

只有 通用语法 提供了 RFC 定义的查询组件,并且该语法要求在第一个冒号 (:) 方案后.

The URI syntax does not require that the scheme-specific-part have any general structure or set of semantics which is common among all URI. However, a subset of URI do share a common syntax for representing hierarchical relationships within the namespace. This "generic URI" syntax consists of a sequence of four main components:

<scheme>://<authority><path>?<query>

each of which, except <scheme>, may be absent from a particular URI. For example, some URI schemes do not allow an <authority> component, and others do not use a <query> component.

absoluteURI   = scheme ":" ( hier_part | opaque_part )

...

hier_part     = ( net_path | abs_path ) [ "?" query ]
net_path      = "//" authority [ abs_path ]>
abs_path      = "/"  path_segments

上述两个 RFC 已 obsoleted by RFC 3986, but for backwards-compatibility reasons Java's existing API and behavior is unlikely to be changed

URI 实现不同于较新的 RFC,不仅在于它如何定义 URI 的有效组件,而且在行为上。例如,参见:

  • Is Java's URI.resolve incompatible with RFC 3986 when the relative URI contains an empty path?

快速搜索找到至少一个开源 library 试图提供与 RFC 3986 兼容的实现,但之前的 link 既不是认可也不是推荐。与基于 java.net.URI 的现有 API 的兼容性可能有限。