单页应用程序应该如何提供永久链接?

Posted

技术标签:

【中文标题】单页应用程序应该如何提供永久链接?【英文标题】:How should single page applications provide permalinks? 【发布时间】:2016-09-02 03:03:28 【问题描述】:

为通过单页应用程序管理的资源提供可公开访问的 URL 的约定是什么?我认为这是一个架构设计问题,但我预计在 AngularJS 中开发一个 SPA,以防万一。我是 SPA 新手。

用户将通过 SPA 创建、查看和修改各种资源(例如基于服务器的对象)。公众也可以通过永久链接 URL 访问这些相同的资源。我对 SPA 在访问资源的永久链接 URL 时向访问者显示资源感到满意。

我只能想到这两种方法:

    将所有资源放在http://example.com/resourcetype/resourceID,在此处实现 RESTful API(改变 HTTP 方法)。 将所有永久链接放在http://example.com/resourcetype/resourceID 并让SPA 点击http://example.com/api/resourcetype/resourceID

(在/api 下设置永久链接似乎不合理。“永久链接”是指资源的公共未登录 URL。)

我希望通过 SPA 导航到资源的用户到达可共享的 URL,因为想要共享该页面的用户会首先考虑共享其 URL,而不是首先找到指向永久链接的链接页。这建议使用第一种方法,但第二种方法更适合通过 URL 对 API 进行版本控制,例如 /api/v1/api/v2 等。

最好避免 URL 中的哈希值。我知道我可以在 AngularJS 中使用 html5 模式将它们隐藏在支持该模式的浏览器中。这也需要服务器端支持,我已经看到将深层链接重写为指向 SPA 访问 URL 的链接的解决方案。

我想知道人们实际在做什么,以及人们是否发现自己在实践中限制了 SPA 的使用。感谢您的帮助!

【问题讨论】:

此页面询问 AngularJS 是否仅适用于 SPA 提供了丰富的信息。它提到为不同的站点资源提供不同的 AngularJS 客户端。 ***.com/questions/15231251/… 这里有一个有用的讨论,关于 SPA 什么时候有帮助,什么时候没有。 news.ycombinator.com/item?id=9879685 【参考方案1】:

这是所有 SPA 的一个很好理解但严重缺乏沟通的弱点。为了在我们的 Vue 应用程序中支持永久链接(和动态 URL),我们使用 Web 服务器 URL 重写。我们创建了一个 Apache 重写规则,用于侦听特定的已知/保留的永久链接或动态 URL 模式,并使用引用所需资源的自定义查询字符串参数将请求重写到 SPA 的唯一可行端点(即/index.hml)。

例如:

RewriteEngine On
RewriteRule ^somemodule/(.*?)$ /?somemodule=$1 [R=301,L]

上面的规则监听mywebsite.com/somemodule/32之类的请求URL,并将其重写为mywebsite.com/index.html?somemodule=32

我们的 Vue 应用程序使用“中间件”组件检查所有请求,寻找匹配 ?somemodule=x 的保留查询字符串参数。当它遇到这种情况时,它会在内部将请求路由到正确的组件/模块。

在 SPA 中处理永久链接和动态 URL 非常麻烦。希望上面的方法可以提供一些额外的思考。

【讨论】:

哎呀。我可以看到这会做到。我可能在 5.5 年前发布了这个问题,但我很快就会再次面临这个问题,所以您的回复很及时。非常感谢!【参考方案2】:

在我们的办公室,我们同时使用resourceIdsslugs。任何可共享资源都将具有由资源模型的属性生成的slug 属性。例如,为我们的 SPA 撰写文章的任何人都必须为文章命名。该标题在保存时由服务器验证,以确保没有其他文章包含相同的标题。如果标题是唯一的,则会为该资源生成一个slug 并保存到我们的数据库中,否则服务器会响应一条错误消息,指出标题不是唯一的。

然后在我们的状态声明中,当用户访问 http://example/articles/article-slug 时,我们会查询我们的 API 以查找与 article-slug 匹配的文章,如果没有找到文章,则返回 404。

        .state('app.articles.article', 
            url: '/:slug',
            views: 
                articles: 
                    templateUrl: tpl + 'views/frontend/articles.article.html',
                    controller: 'ArticleCtrl',
                    resolve: 
                      article: ['$stateParams', function ($stateParams) 
                            var slug = $stateParams.slug;
                            // query API for slug
                      ]
                    
                
            
        )

【讨论】:

有趣。因此,当您的 SPA 生成新资源时,它会基于未针对资源类型的路径组件寻址的 slug 创建永久链接?这是否意味着每个资源都有两个访问点?两者都可以公开分享吗? 你给了我一个想法,虽然这个想法可能是你的意图。我可能能够通过仅使用 slug 而从不使用特定于资源类型的 ID 来缓解变化的永久链接问题。一个基本 URL 将是所有对象的单一访问点,并且导航到一个对象的用户甚至会从 SPA 到达这个永久链接 URL。 (除了这似乎是我的选项 1,SPA 在域根目录中,并且在 URL 中没有指示 API 版本。)

以上是关于单页应用程序应该如何提供永久链接?的主要内容,如果未能解决你的问题,请参考以下文章

如何禁用通过 IIS 提供的单页应用程序 HTML 文件的缓存?

如何增强单页应用的体验

如何在单页应用(spring security)中提供 CSRF Token?

3.2.8 Google Tag Manager实战指南——虚拟页面跟踪单页应用

如何避免单页应用程序中的 CORS 预检请求?

如何在单页应用程序 (SPA) 的特定页面中隐藏对讲聊天小部件?