问题
Web 开发路由跳转常见的一个需求:一个路由(A)到另一个路由(B)的同时会带点参数。通常情况下我们会把参数放到 URL 的 query 里面去比如:
https://example.com:8042/over/there?name=ferret
\_________/
|
query
# \_________/ 来源:https://github.com/Cyphrme/URLFormJS/blob/master/README.md?plain=1
query 非常好用,正常满足了需求,而利于用户分享。哪怕 query 里面的参数多点也没问题,通常情况下我们都不会超过浏览器对 URL 大小的限制。
这也就是讲路由之间串亲戚都比较抠,不会带太贵重的礼物,现在加入极端情况下,路由(A)到路由(B)携带的参数过大(比如很多很多查询条件),这就很危险,URL 过长很有可能截断。
现在我们让用户保存分享的便利情况下如何实现这个需求呢?
fragment
答案就是使用 URL 的 fragment,即 hash 路由传参而不使用 query 传参。
https://example.com:8042/over/there?name=ferret#balabalabalab
\___________/
|
fragment
浏览器路由 fragment 的好处在于:
- 保留了分享功能,带有 Fragment 的链接,其他人可以访问同样的页面。
- 节省了 HTTP 资源,因为 Fragment 的内容不会被发送到服务器。
- 存储无限制: Fragment 路由还可以用来管理应用程序的状态。因为不发送给服务端,浏览器不会限制 Fragment 的长度,一个大小毫无限制的存储器诞生了。
实现
JSON 肯定不能直接显示在 URL 中,所以使用最常用的百分比编码进行编码解码,下面代码的 compress 主要压缩空格和缩进去。
编码:
const stateString = JSON.stringify(appState, null, null); // appState is a json object
const encoded = encodeURIComponent(stateString); // Push that `encoded` string to the url
解码
const decoded = decodeURIComponent(encoded); // same encoded as above, but read from url
const newState = JSON.parse(decoded); // Now load your application with the newState
Fragment 应用
knotend 是一个用来画流程图的工具,但是它的数据并没有存储在后端,而是选择了存储在 URL 的 Fragment 中,这就牛皮了,无限无成本存储,不用请求接口用户打开超快,还可以通过 URL 分享,恢复和重做功能直接利用浏览器的前进后退就能完成。
唯一的缺点就是 URL 可能过于臃肿。