7

每个 Web 应用程序 - 每个网站 - 都是一项服务。(...) 使 Web 站点易于网络冲浪者使用的特性也使 Web 服务 API 易于程序员使用。

Richardson 和 Ruby,“RESTFul Web 服务”

正如我所期望的那样,一个同时也是 Web 服务的网站根据用户代理请求的内容提供其资源的多种表示形式。API,可以这么说,是网站本身,并不单独提供。

许多流行的“REST API”并非如此。例如,Twitter 的 API 位于http://api.twitter.com/1/,URI 中的“1”是 API 本身的版本。Socialcast 还在https://demo.socialcast.com/api/提供了一个 REST API ,第三级名称是它所寻址的网络的名称。

这对我来说似乎是错误的。如果我在http://www.example.com/blog有我的博客,我不需要在不同的位置提供 API,只为机器人提供 JSON。与其拥有http://www.example.com/blog/posts/http://api.example.com/blog/posts这两个不同的 URI,我应该只拥有前者,并且可以使用多种表示形式,其中application/json对于我希望提供给我的用户的 JSON API。

示例 1:浏览器询问我博客上的帖子;

要求:

curl -i \
 -H "Accept: text/html" \
 -X GET \
 http://www.example.org/blog/posts/

回复:

 200 OK
 Content-Type: text/html; charset=utf-8

 <html><body><h1>Posts</h1><ol><li><h2>My first post ...

示例 2:相同的 URI,但这次是机器人发出请求;

要求:

curl -i \
 -H "Accept: application/json" \
 -X GET \
 http://www.example.org/blog/posts/

回复:

 200 OK
 Content-Type: text/html; charset=utf-8

 {
    "posts": [
        {
            "id": 1,
            "title": "My first post" ...

API 的版本号应编码在请求标头的“Accept”字段中,最重要的是避免像 Twitter 那样强烈键入 URI(“statuses/show.json?id=210462857140252672”或“statuses/show/210462857140252672.json ”)。

如果采用统一的方法,我可能会失去一些灵活性(但是,Cool URI 不应该永远不会改变吗?),但我认为坚持 REST(或至少我对它的解释)会提供更多好处。

哪种方法更正确:分离 API 和网站,还是统一它们?

4

4 回答 4

8

这里没有对错。当您的 API 开发是由特定的客户端需求驱动时,过于紧密地遵循 REST 和 RFC 可能会变得很困难。

实际上,与 API 客户端相比,人类用户具有不同的行为模式,因此需要不同的处理方式。最生动的区别在于,许多 API 都是数据密集型的,专为批量操作和数据转储而设计,而面向人类用户的应用程序更“反应性”,并且经常一步一步、一个请求一个请求地做事。因此,在许多项目中,API 的 URL 设计进行了优化,以避免在多次网络往返和重复存储调用上浪费客户端和服务器资源。

在底层,API 实现通常具有与核心应用程序不同的设计,针对 API 提供的操作类型进行了优化。例如,API 实现可能使用单独的缓存策略。现在,如果您将代码拆分出来,您可能希望创建一个仅处理 API 调用的主机集群。这就是将 API 放在另一个域上对负载管理有益的地方:一个单独的域允许在高负载站点上进行更简单的负载平衡。相比之下,当您在同一个域名(但有单独的集群)上使用 /api URL 前缀时,您需要一个智能(L7 感知)负载均衡器来完成在 API 和 Web 前端集群之间拆分请求流的工作,但是这样的负载均衡器更昂贵。

因此,Twitter 之类的公司将 API 分离出来可能有很好的技术原因,但对其他实现的引用可能不适用于您的项目。如果您处于设计的早期阶段,您可能希望从同一域上的统一 URL 方案开始,但最终您可能会发现有很好的实际用例使您改变方法,然后...重构。

PS 这里有一个关于版本控制的冗长讨论 - API 版本控制的最佳实践?

PSS 我发现强类型 URL 有助于快速调试。您可以简单地使用 .json 将 URL 放入浏览器并快速获得结果,而无需切换到命令行。但同意你的观点,“接受”标题是首选方法

用于 API 的 PSSS SEO?我可以看到一个好的 URL 设计是如何有益的,但对于搜索引擎来说,如果您的服务在同一路径/域名上提供多种输出格式,它可能无关紧要。归根结底,搜索引擎是为人类用户构建的,人类用户不会使用 XML 和 JSON。

于 2013-03-18T09:55:07.317 回答
2

Web 和 RESTful API 的行为方式可能不同。

理论上,一个请求如何http://mysite.com/blog/1区分它需要返回一个 HTML 页面还是只返回数据(JSON、XML ......)?我将投票支持使用Accept http 标头

Accept: text/html <-- Web browsers
Accept: application/json <-- Applications/Relying parties consuming data or performing actions

为什么 Twitter、Facebook 或其他网站不混合使用 Web 浏览器和依赖方?老实说,我认为这是一个武断的决定。

也许我可以提供一个可能的原因:Web 浏览器/搜索引擎机器人 URL 应该是友好的 URL,因为它们在 SEO 上效果更好。出于这个原因,也许 SEO 就绪的 URL 在 REST 方面不是很语义化,但它们适用于搜索引擎甚至人类用户!

最后:哪个更好(这是我的意见)?

  • 您需要 SEO然后使用单独的 URL
  • 不需要SEO然后统一同域同格式的URL
于 2013-03-12T12:01:26.227 回答
1

我不同意另一个答案,即这个决定应该与 SEO 或 URL 的“友好”程度有关(机器人也是 [由] 人编写的!)。但是我的直觉告诉我,更好的 SEO 结果将来自统一URI,因为这也统一了您的 API URI 从万维网链接到的(不太可能)事件中的 pagerank。

这个决定应该取决于您的服务器和客户端的能力。如果他们可以设置 Accept 请求标头,并且您的服务器足够聪明,可以进行透明的内容协商,那么一定要统一 URI。这就是我所做的(我唯一的 JSON 客户端是我自己,发出从我的 Web 应用程序的其他 HTML 部分提供的 AJAX 请求,我在其中控制 Accept 标头)。

如果客户端无法设置请求标头,例如想要获取 json 响应的 Web 用户,他们最终将使用默认值(可能是 text/html)。出于这个原因,您可能希望允许在唯一 URI(/foo.txt、/foo.rtf)下发生非协商响应。通常这是通过将格式附加到由点分隔的 URI 来完成的,就好像它是文件扩展名一样(但通常不是,mod_rewrite 会做杂耍),以便需要文件扩展名的平台上的旧客户端可以保存文件一个有意义的。

我网站上的大多数页面都是这样工作的:

  1. 根据请求 URL 确定 SQL 查询。(例如/cars?colour=black=> SELECT * FROM cars WHERE colour='black'
  2. 发出 SQL 查询。
  3. 从该文件支持的列表中确定可接受的响应类型。这通常是 HTML 和 HAL(即 JSON),但有时也是 XML。回退到text/html如果没有其他是可以接受的。
  4. if(HTML) 吐出<HEAD><NAV>(考虑参数<h1>Black Cars</h1>:)
  5. 使用最可接受的响应类型吐出结果。
    此函数知道如何获取 SQL 结果对象并将其转换为 HTTPLink标头、HTML<LINK>元素流、HAL 的_links键、XLink 元素流、HTML<TABLE>元素(带有包含<A>元素的单元格)或 CSV 文件。SQL 查询可能返回 0 行,在这种情况下,如果正在使用该输出,则会写入用户友好的消息而不是 HTML 表。
  6. if(HTML) 吐出<FOOTER>

这个基本大纲在我的 web 应用程序中处理了大约 30 个不同的资源集合,尽管每个集合都有一组不同的请求 URI 可能调用的选项,因此每个集合的开始在参数验证方面都不同。

所以,现在我已经解释了所有这些,您可以看到将每个资源的所有细节都放在一个地方处理,以及由通用库函数处理格式 X 或格式 Y 输出的泛型是多么有用。这是一个实现细节,它让我的生活变得轻松,并帮助我坚持不要重复自己的格言。

于 2013-03-12T13:24:16.347 回答
0

我绝对不同意网站 == 网络服务方法。

简单地说,网站应该被视为一个客户端,只是一个客户端,它使用 Web 服务并以适当的形式呈现数据以供 Web 使用。就像移动应用程序是一个客户端,只是一个客户端,使用相同的 Web 服务并以适当的形式呈现数据以供移动使用。

Web 服务是服务提供者。所有其他人都只是客户;网站,android 应用程序,iphone 应用程序,...等。

于 2013-03-19T12:28:23.017 回答