简体   繁体   English

RESTful服务架构问题

[英]RESTful services architecture question

This is question more about service architecture strategy, we are building big web system based on rest services on back end. 这是关于服务架构策略的更多问题,我们正在后端基于REST服务构建大型Web系统。 And we are currently trying to build some internal standards to follow while developing rest services. 我们目前正在尝试建立一些内部标准,以在开发休息服务时遵循。

Some queries returns list of entities, for example lets consider we have image galleries retrieving service: /gell_all_galeries, returning next response: 一些查询返回实体列表,例如,让我们考虑我们有图像画廊检索服务:/ gell_all_galeries,返回下一个响应:

<galleries>
   <gallery>
      <id>some_gallery_id</id>
      <name>my photos</name>
      <photos>
          <photo>
                <id>123</id>
                <name>my photo</name>
                <location>http://mysite/photo/show/123</location>
                ......
                <author>
                     <id>some_id</id>
                     <name>some name</name>
                     .......
                <author>
          </photo>
          <photo> ..... </photo>
          <photo> ..... </photo>
          <photo> ..... </photo>
          <photo> ..... </photo>
    </photos>
  </gallery>
  <gallery> .... </gallery>
  <gallery> .... </gallery>
  <gallery> .... </gallery>
  <gallery> .... </gallery>
</galleries>

As you see here, response quite big and heavy, and not always we need such deep info level. 如您在此处看到的,响应非常大而沉重,并非总是我们需要如此深入的信息。 Usual solution is to use or http://ru.wikipedia.org/wiki/Atom elements for each gallery instead of full gallery data: 通常的解决方案是为每个图库使用或http://ru.wikipedia.org/wiki/Atom元素,而不是完整的画廊数据:

<galleries>
   <gallery>
      <id>some_gallery_id</id>
      <link href="http://mysite/gallery/some_gallery_id"/>
   </gallery>
   <gallery>
      <id>second_gallery_id</id>
      <link href="http://mysite/gallery/second_gallery_id"/>
   </gallery>
  <gallery> .... </gallery>
  <gallery> .... </gallery>
  <gallery> .... </gallery>
  <gallery> .... </gallery>
</galleries>

The first question, is next: maybe instead we shouldn't even use and types, and just use generic and for all resources that return list objects: 接下来的第一个问题是:也许相反,我们甚至不应该使用和类型,而只对返回列表对象的所有资源使用通用和:

 <list>
  <item><link href="http://mysite/gallery/some_gallery_id"/></item>
  <item><link href="http://mysite/gallery/other_gallery_id"/></item>
  <item>....</item>
</list>

And the second question, after user try to retrieve info about some concrete gallery, he'll use for example http://mysite/gallery/some_gallery_id link, what should he see as results? 第二个问题,在用户尝试检索有关某个具体画廊的信息之后,他将使用例如http:// mysite / gallery / some_gallery_id链接,他应该如何看待结果?

Should it be: 应该是:

   <gallery>
      <id>some_gallery_id</id>
      <name>my photos</name>
      <photos>
          <photo>
                <id>123</id>
                <name>my photo</name>
                <location>http://mysite/photo/show/123</location>
                ......
                <author>
                     <id>some_id</id>
                     <name>some name</name>
                     .......
                <author>
          </photo>
          <photo> ..... </photo>
          <photo> ..... </photo>
          <photo> ..... </photo>
          <photo> ..... </photo>
    </photos>
  </gallery>

or : 要么 :

   <gallery>
      <id>some_gallery_id</id>
      <name>my photos</name>
      <photos>
          <photo><link href="http://mysite/photo/11111"/></photo>
          <photo><link href="http://mysite/photo/22222"/></photo>
          <photo><link href="http://mysite/photo/33333"/> </photo>
          <photo> ..... </photo>
    </photos>
  </gallery>

or 要么

   <gallery>
      <id>some_gallery_id</id>
      <name>my photos</name>
      <photos>
          <photo>
               <link href="http://mysite/photo/11111"/>
               <author>
                    <link href="http://mysite/author/11111"/>
               </author>
           </photo>
          <photo>
               <link href="http://mysite/photo/22222"/>
               <author>
                    <link href="http://mysite/author/11111"/>
               </author>
           </photo>
          <photo>
               <link href="http://mysite/photo/33333"/>
               <author>
                    <link href="http://mysite/author/11111"/>
               </author>
           </photo>
          <photo> ..... </photo>
    </photos>
  </gallery>

I mean if we use link instead of full object info, how deep we should go there? 我的意思是,如果我们使用链接而不是完整的对象信息,那我们应该走多深? Should I show an author inside photo and so on. 我应该在照片里面给作者看吗?

Probably my question ambiguous, but what I'm trying to do is create general strategy in such cases for all team members to follow in future. 我的问题可能不明确,但是我想做的是在这种情况下制定总体战略,以供所有团队成员将来遵循。

There really is no right or wrong answer to "how should I design my media types". 对于“我应该如何设计媒体类型”,确实没有正确或错误的答案。 However, there are a few very important guidelines when selecting existing and designing new media types. 但是,在选择现有媒体和设计新媒体类型时,有一些非常重要的准则。

RESTful systems achieve scalability through careful use of caching . RESTful系统通过谨慎使用缓存来实现可伸缩性 Designing your resources to break down content into chunks that have similar data volatility. 设计资源以将内容分解为具有类似数据波动性的块。 For example, with your scenario, you have a list of galleries that contain photos. 例如,对于您的方案,您具有包含照片的画廊列表。 My guess would be that you don't add/remove galleries very often, but you do add/remove photos regularly. 我的猜测是您不经常添加/删除画廊,但是您会定期添加/删除照片。 Therefore it would make sense to ensure that you could get a list of galleries that has no photo information. 因此,确保您可以获得没有照片信息的画廊列表是很有意义的。 That would make it easy to cache that response. 这将使缓存该响应变得容易。

Optimizing the size of responses can be important for performance, but caching is way more important . 优化响应的大小对于性能可能很重要,但是缓存则更为重要 Sending 0 bytes across the wire is always more efficient. 通过网络发送0字节总是效率更高。

Even though the list of photos may change more regularly you can still using caching effectively. 即使照片列表可能会更定期地更改,您仍然可以有效地使用缓存。 By using the if-modified-since header or etags , you will not save the network roundtrip, but you can save lots of bandwidth by not transferring representations that are unchanged. 通过使用if-modified-since标头或etags ,将不会保存网络往返,但可以通过不传输不变的表示形式来节省大量带宽。

It is extremely difficult to design resources that are ideal for all circumstances and because of this I suggest you do not try. 设计适合所有情况的理想资源非常困难 ,因此,建议您不要尝试。 Design resources that work well for your particular use cases. 设计适合您特定用例的资源。 If other use cases arise create new resources to handle those. 如果出现其他用例,请创建新资源来处理这些用例。

There is nothing wrong with creating: 创建没有错:

/gallery/foo/quickview
/gallery/foo/detailedview
/gallery/foo/justlinks

You want to use a web framework that makes it really easy and cheap to create new resources . 您想使用一个Web框架,它使创建新资源变得非常容易且便宜 Resources will rarely have a one-to-one mapping with your domain entities, so feel free to create as many resources as you need. 资源很少会与您的域实体进行一对一的映射,因此可以随意创建所需数量的资源。

My last comment is regarding the selection of a media-type. 我最后的评论是关于媒体类型的选择。 You should really consider using something like Atom for a service like this. 您应该真正考虑将像Atom这样的东西用于这样的服务。 Atom is ideal for managing lists of things and it has all the mechanisms in place to handle media elements like photos. Atom是管理事物列表的理想选择,它具有处理诸如照片等媒体元素的所有机制。

Most people when they start using REST services get used to the idea that they can deliver straight application/xml or application/json as a media type. 大多数人在开始使用REST服务时就习惯了这样的想法,即他们可以将直接的application / xml或application / json作为媒体类型交付。 There are some specialized cases where this is completely feasible, however as you start to implement more of the REST constraints you will find these generic media type formats will limit the benefits you can achieve in many cases . 在某些特殊情况下,这是完全可行的,但是,当您开始实施更多的REST约束时,您会发现这些通用媒体类型格式将限制您在许多情况下可以获得的收益 For the moment, don't worry too much about it just be aware that it is always safer to pick a "real" media type like application/xhtml, RDF or Atom, and if you do choose application/xml you may run into difficulties later on. 目前,不必担心太多,只是要知道选择“真实”媒体类型(例如application / xhtml,RDF或Atom)总是比较安全,如果您选择application / xml,则可能会遇到麻烦稍后的。

A good thing to consider is how you intend for clients to retrieve the data. 要考虑的一件好事是您打算如何让客户端检索数据。 If you're intending for a client to grab a whole bunch of information about many photos, then a list of only <photo href="..."/> might not be optimal, since the client would then be forced to perform a GET request for each photo resource they need information about. 如果您打算让客户获取有关许多照片的全部信息,那么仅<photo href="..."/>可能不是最佳选择,因为这样一来,客户将被迫执行获取他们需要的有关每个照片资源的GET请求。

I can think of a couple interesting ways around this off the top of my head. 我可以想到一些有趣的方法来解决这个问题。

You could allow a client to specify the fields they'd like to retrieve as query parameters when querying the list, eg: 您可以允许客户端在查询列表时将其想要检索的字段指定为查询参数,例如:

GET http://www.example.com/photos?_fields=author,fileSize

This could then return something like: 然后,可能返回如下内容:

<photos href="/photos?_fields=author,fileSize">
    <photo href="/photos/15">
        <author href="/authors/2245"/>
        <fileSize>32MB</fileSize>
    </photo>
    ...
</photos>

Alternatively, you could make it simpler by allowing the client to specify some sort of maximum "depth" property; 或者,可以通过允许客户端指定某种最大的“深度”属性来简化操作。 this is a bit more crude, but could be used effectively. 这有点粗糙,但可以有效地使用。 For example, if the client specified a depth of 2, you'd return everything under <gallery> , as well as all child elements of each <photo> . 例如,如果客户端指定深度为2,则将返回<gallery>下的所有内容以及每个<photo>所有子元素。

GET /galleries?depth=2

Might return something like: 可能会返回类似:

<galleries>
  <id>22</id>
  <name>My Gallery</name>
  <!-- full gallery data -->
  <photos href="/photos?gallery=/galleries/22">
    <photo href="/photos/99">
      <id>99</id>
      <author href="/authors/4381"/><!-- href instead of including nested author data -->
      <fileSize>24MB</fileSize>
      <!-- full photo data -->
    </photo>
    ...
  </photos>
</galleries>

Alongside of this, if you're concerned about the client querying many, many records at once (eg if there are thousands of photos or galleries), you might want to consider some sort of paging for your lists. 除此之外,如果您担心客户端一次查询很多条记录(例如,如果有成千上万张照片或图库),则可能需要考虑对列表进行某种分页。 This might involve setting a hard maximum for results in your code and providing the client with links to next/previous pages: 这可能涉及为代码中的结果设置一个硬性最大值,并为客户端提供指向下一页/上一页的链接:

GET /photos?gallery=/galleries/59

Might return: 可能返回:

<photos href="/photos?gallery=/galleries/59&_max=100&_first=100" next="/photos?gallery=/galleries/59&_max=100&_first=200" prev="/photos?gallery=/galleries/59&_max=100&_first=0" count="100" total="3528">
    ....
</photos>

Clients could control the _first and _max properties, but could never increase the _max over a certain configured threshold. 客户端可以控制_first_max性质,但永远不会增加_max超过一定配置的阈值。 You would return the number of "found" results for the page in the markup as well as the total number of results available. 您将在标记中返回页面的“找到的”结果数以及可用结果总数。 This would help you cut back on the response sizes, which you mentioned might be a concern. 这将帮助您减少响应大小,您可能会提到此问题。 This could be done in parallel with the options listed above. 可以与上面列出的选项同时进行。

Ultimately it's up to how you want your server to instruct the clients to retrieve data. 最终,这取决于您希望服务器如何指示客户端检索数据。 If you don't want them doing a GET for each photo then you might want to provide them more convenient ways to get deeper data. 如果您不希望他们为每张照片做一次GET,那么您可能想为他们提供更方便的方法来获取更深的数据。 But if you think your server can handle decent load, and along with that you can make server-side optimizations (caching, using 304 statuses, etc.), then just returning shallow lists with href s is a bit more straightforward. 但是,如果您认为服务器可以处理适当的负载,并且可以同时进行服务器端优化(缓存,使用304状态等),则仅返回带有href的浅表会更简单一些。

This really depends on your scenario. 这确实取决于您的情况。 You need to know how the client is going to use this to know how to design your Resource Proxies . 您需要知道客户端将如何使用它来了解如何设计资源代理

I suggest you don't get lost in the "choice crossroad". 我建议您不要在“选择十字路口”迷路。 Just go with one implementation based on what you assume about the client usage . 只需根据您对客户端使用情况的假设进行一个实现即可。 See how the whole thing is used and behaves, fine tune afterwards if needed. 查看整个事物的用法和行为,然后根据需要进行微调。 Wash. Rinse. 洗净,漂洗。 Repeat. 重复。 Do it the permanent Beta way :) 做永久的Beta版方式:)

You can always use attributes. 您可以随时使用属性。

  <gallery id = "1" name = "Gallery 1">
      <photos>
          <photo id="1" link="http://mysite/photo/11111" />
          <photo id="2" link="http://mysite/photo/22222" />
          <photo id="3" link="http://mysite/photo/33333" />
      </photos>
  </gallery>

Or you can use JSON I prefer it since its easier and lighter than XML. 或者您可以使用JSON,我更喜欢它,因为它比XML更轻松,更轻松。

{
    "gallery": {
        "id": "1",
        "name": "Gallery 1",
        "photos": [
            {
                "id": "1",
                "link": "http://mysite/photo/11111" 
            },
            {
                "photo": "2",
                "link": "http://mysite/photo/22222" 
            },
            {
                "photo": "3",
                "link": "http://mysite/photo/33333" 
            } 
        ] 
    } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM