How can I avoid hardcoding URLs in a RESTful client/server web app with deep linking?
我正在开发一个 SPA,它是 RESTful Web 服务的客户端。客户端和服务器都是同一个项目的一部分,即我可以自由修改双方的代码。我一直在阅读 RESTful API 设计,以尝试确保我以"正确"的方式做所有事情。我从阅读中得到的一个收获是,RESTful 服务应该发布超链接,以便客户端可以访问更多信息,并且客户端除了入口点之外不应该有关于服务 URL 的硬编码信息。使用超链接可以让客户端在服务器更改 URL 时更加灵活。
但是,当允许用户链接到特定客户端状态时,我无法弄清楚该架构应该如何工作。例如:
其中一个视图是可供购买的图书列表。客户端将浏览器的位置设置为 /books/ 以标识此页面,后端数据来自端点 /api/books/,从发布该 URL 的 API 入口点检索。服务 URL 响应如下 JSON 文档:
1 2 3 4 5 6 7 8
| [
{"title":"The Great Gatsby",
"id": 24,
"url":"http://localhost/api/books/24/"},
< and so on >
] |
客户端使用它来生成可读的链接,当点击这些链接时,会转到单本书的详细视图。浏览器的位置已更新为 /books/the-great-gatsby/24/,因此用户可以将此视图添加为书签并链接到它。
当用户直接点击该链接时,客户端如何处理?如果没有硬编码的 URL,它如何知道从哪里获取本书的信息?
我能想到的最好的方法是以下请求序列:
GET /api/ - 查看可用的服务(以查找是否有书籍)
OPTIONS /api/books/ - 查看书籍上可用操作的描述(例如,它可以确保它可以通过 ID 找到书籍)
GET /api/books/?id=24 - 查看它是否可以找到 ID 与浏览器位置中的 ID 匹配的书籍。
GET /api/books/24/ - 实际检索数据
任何较短的内容都意味着客户端对 API 的 URL 具有硬编码知识。但是,从 Web 应用程序的angular来看,这似乎非常低效。
我错过了什么技巧吗?有没有办法让客户端"知道"如何在不以某种方式硬编码 /api/books/24/ 端点的情况下获取有关图书 ID 24 的更多详细信息?
- 如果您让用户为 URL 添加书签,那么您需要在服务器上支持该位置。我不会称之为硬编码信息。
-
也许我不理解您的架构:如果有生成 URL 的客户端代码,那么由客户端重新生成内容。所以你想知道在这种情况下在哪里存储 http:localhostapibooks24 ?
-
@JochenBedersdorfer 完全正确 - 我没有看到在我的 Javascript 代码中硬编码该 URL 构建器的替代方法,以便我可以有效地呈现 booksthe-great-gatsby24 视图。
-
如果服务器最初生成页面,则没有什么可以阻止它在其 head 中添加 http:localhostapibooks24 作为 link 标记
-
服务器不渲染任何页面,它只是为 JS 应用程序服务。即使这样做了,这样的链接标签仍然会将客户端和服务器耦合在一起(它只是知道如何解析客户端位置的服务器)
如果您从服务器请求此资源 /books/the-great-gatsby/24/,服务器应该以特定于该 URL 的内容进行响应。目前,您可能正在分析 window.location 这有点 hack。
如果 /books/the-great-gatsby/24/ 是静态内容,那么您几乎没有选择:您将客户端的当前状态显式存储在某处(即 /books?data=api/books/24 或隐式 /books/the-great-gatsby/24/ 这导致客户端必须知道如何将其转换为 API 资源。
RESTful 方式是使用超文本来指示任何相关资源(即要呈现的数据)在哪里,这使得标签成为一个合适的选择。
即抛弃静态内容,用 <head><link href="api/books/24" ....></link></head>
渲染 /books/the-great-gatsby/24/
但是,如果您始终保留对客户端的控制权并且不打算将 API 发布给第三方,那么放弃 RESTful 并转而使用 RESTish 可能会更有效率。
另一个想法:
您已经做出了以下假设,具有路径组件 /books/the-great-gatsby/24/ 的 url 应该以某种方式映射到具有类似 /api/books/24/ 的路径的 url。
为什么不添加一个小型服务服务器端来为您进行此映射?例如:
1
| /lookup?url=/books/the-great-gatsby/24/ |
如果您担心额外的请求,该端点可以只返回实际响应。它仍然可以有一个引用真实 url 的 self 链接(或规范,如果您愿意)。
或者它可以只是重定向,并使用 HTTP/2 立即推送真实资源。