Hash模式下,query在hash前无法获取到

Version
4.0.14

Reproduction link
http://demo.heyj.top/

如果hash在前query在后,如:http://localhost:8090/#/login?query=121
使用浏览器的 location.search 也是获取不到,java中的URL类也一样,不知道这个是bug还是设计如此?

号后面的都是 hash,没有 location.search 了。

#/login?query=121 全是 hash。

./vue.html?aa=10#/page,

按照 js 来看 ?aa=10 是 location.search ,#/page 是hash

./vue.html#/page?aa=10

按照 js 来看 ,没有 location.search ,#/page?aa=10 是hash

按照 路由设置 page 是path,aa=10 是 query。没有问题。

先说结论,这是正常的。

可以先了解一下什么是 URL (Uniform Resource Locators),在 rfc3986 中统一称为 URI: rfc3986 1

楼主说的 location.search 对应的是 Query String 部分,而 # 字符及其后面的字符统称为 Fragment,关于这部分的定义可以参考 rfc3986 3.5 这部分。

Fragment 的用处并非只有用于路由,平时可以多留意下,最常见的比如 a 链接中 Fragment 是用于锚点而非路由。

VueRouter 只是借助 URL 中的 Fragment 部分实现了路由。所以这部分的定义仅限于 VueRouter 内部。

举个例子,如果没有 VueRouter 解析,那么 http://example.com/path?id=1#/page?r=12 这个 URL 只有这么几个部分:

location.protocol = http:
location.hostname = example.com
location.pathname = /path
location.hash = #/page?r=12

在加入 VueRouter 之后,其内部才对 hash 进行了解析,所以我们只能从应用内部获取这部分信息,比如:

created() {
  this.$route.path // /page
  this.$route.query // { "r": "12" }
}

当然,因为 VueRouter 采用了和 URL 一致的规范,所以并非一定要在 VueRouter 中,我们也可以将这部分字符串当成 URL 自己解析即可,这只是非常简单的字符串处理而已。

举个例子,楼主希望在后端通过 URL 类处理,以 JavaScript 为例:

const url = 'http://example.com/path?id=1#/page?r=12'
// 只是伪代码例子,实际以对应 URL 类的使用方式为准
const parse = new URL('http://a.com' + url.split('#')[1])
parse.path // /page
parse.query // { "r": "12" }

注意几点:

  1. 因为按照楼主要求只是为了解析 Hash 模式下 URL 中的 Query String,所以上面的例子建立在你只对 hash 中的 path 和 query string 感兴趣的前提。
  2. 通常情况建议这种处理应该在前端实现,将路由参数传递给后端。尽量避免在 VueRouter 外解析 Fragment。