网站是否也应该是Web资源?

时间:2013-03-12 11:51:32

标签: http rest web url-design

  

每个网络应用程序 - 每个网站 - 都是一项服务。 (...)使网站易于使用的网站功能也使网络服务API易于程序员使用。

     

Richardson和Ruby,“RESTFul Web Services”

正如我所预料的那样,同时也是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”或“status / show / 210462857140252672.json“)。

通过采用统一的方法我可能会失去一些灵活性(但是,不应该Cool URIs never change?),但我认为坚持REST(或者至少我对它的解释)会提供更多的好处。

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

4 个答案:

答案 0 :(得分:7)

这里没有对错。当您的API开发受特定客户端要求驱动时,REST和RFC过于紧密可能会很困难。

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

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

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

P.S。关于版本控制的讨论很长 - Best practices for API versioning?

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

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

答案 1 :(得分:2)

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

理论上,如果需要返回HTML页面或仅返回数据(JSON,XML ...),http://mysite.com/blog/1之类的请求会如何区分?我会投票使用Accept http标头

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

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

也许我可以提供一个可能的原因:Web浏览器/搜索引擎机器人URL应该是 friendly-URLs ,因为这些在SEO上工作得更好。出于这个原因,也许SEO准备好的URL在REST方面不是非常语义,但它们适用于搜索引擎甚至是人类用户!

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

  • 您需要SEO 然后使用单独的网址
  • 您不需要搜索引擎优化然后统一同一域和格式的网址

答案 2 :(得分:1)

我不同意另一个答案,即这个决定应该与SEO有关,或者URL是多么“友好”(机器人也是由人写的!)。但我的直觉告诉我,更好的搜索引擎优化结果将来自统一 URI,因为这也会在您的API URI将从世界狂野网络链接到的(不太可能的)事件中统一pagerank。

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

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

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

  1. 从请求URL确定SQL查询。 (例如/cars?colour=black =&gt; 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结果对象并将其转换为HTTP Link标头,HTML <LINK>元素流,HAL的_links键,XLink元素流,HTML { {1}}元素(包含<TABLE>个元素的单元格)或CSV文件。 SQL查询可能返回0行,在这种情况下,如果正在使用该输出,则会写入用户友好的消息而不是HTML表。
  6. if(HTML)吐出<A>
  7. 这个基本大纲处理我的Web应用程序中大约30个不同的资源集合,尽管每个资源集合都有一组请求URI可以调用的不同选项,因此每个资源集合的开头在参数验证方面都有所不同。

    所以,现在我已经解释了所有这些,你可以看到在一个地方处理每个资源的所有细节可能是有用的,以及通过公共库函数处理格式X或格式Y的泛型。这是一个实现细节,可以减轻我的生活,并帮助我坚持不要重复自己的格言。

答案 3 :(得分:0)

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

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

网络服务是服务提供商。所有其他人都只是客户;网站,Android应用程序,iPhone应用程序等......