[英]RESTful services architecture question
這是關於服務架構策略的更多問題,我們正在后端基於REST服務構建大型Web系統。 我們目前正在嘗試建立一些內部標准,以在開發休息服務時遵循。
一些查詢返回實體列表,例如,讓我們考慮我們有圖像畫廊檢索服務:/ 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>
如您在此處看到的,響應非常大而沉重,並非總是我們需要如此深入的信息。 通常的解決方案是為每個圖庫使用或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>
接下來的第一個問題是:也許相反,我們甚至不應該使用和類型,而只對返回列表對象的所有資源使用通用和:
<list>
<item><link href="http://mysite/gallery/some_gallery_id"/></item>
<item><link href="http://mysite/gallery/other_gallery_id"/></item>
<item>....</item>
</list>
第二個問題,在用戶嘗試檢索有關某個具體畫廊的信息之后,他將使用例如http:// mysite / gallery / some_gallery_id鏈接,他應該如何看待結果?
應該是:
<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>
<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>
要么
<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>
我的意思是,如果我們使用鏈接而不是完整的對象信息,那我們應該走多深? 我應該在照片里面給作者看嗎?
我的問題可能不明確,但是我想做的是在這種情況下制定總體戰略,以供所有團隊成員將來遵循。
對於“我應該如何設計媒體類型”,確實沒有正確或錯誤的答案。 但是,在選擇現有媒體和設計新媒體類型時,有一些非常重要的准則。
RESTful系統通過謹慎使用緩存來實現可伸縮性 。 設計資源以將內容分解為具有類似數據波動性的塊。 例如,對於您的方案,您具有包含照片的畫廊列表。 我的猜測是您不經常添加/刪除畫廊,但是您會定期添加/刪除照片。 因此,確保您可以獲得沒有照片信息的畫廊列表是很有意義的。 這將使緩存該響應變得容易。
優化響應的大小對於性能可能很重要,但是緩存則更為重要 。 通過網絡發送0字節總是效率更高。
即使照片列表可能會更定期地更改,您仍然可以有效地使用緩存。 通過使用if-modified-since標頭或etags ,將不會保存網絡往返,但可以通過不傳輸不變的表示形式來節省大量帶寬。
設計適合所有情況的理想資源非常困難 ,因此,建議您不要嘗試。 設計適合您特定用例的資源。 如果出現其他用例,請創建新資源來處理這些用例。
創建沒有錯:
/gallery/foo/quickview
/gallery/foo/detailedview
/gallery/foo/justlinks
您想使用一個Web框架,它使創建新資源變得非常容易且便宜 。 資源很少會與您的域實體進行一對一的映射,因此可以隨意創建所需數量的資源。
我最后的評論是關於媒體類型的選擇。 您應該真正考慮將像Atom這樣的東西用於這樣的服務。 Atom是管理事物列表的理想選擇,它具有處理諸如照片等媒體元素的所有機制。
大多數人在開始使用REST服務時就習慣了這樣的想法,即他們可以將直接的application / xml或application / json作為媒體類型交付。 在某些特殊情況下,這是完全可行的,但是,當您開始實施更多的REST約束時,您會發現這些通用媒體類型格式將限制您在許多情況下可以獲得的收益 。 目前,不必擔心太多,只是要知道選擇“真實”媒體類型(例如application / xhtml,RDF或Atom)總是比較安全,如果您選擇application / xml,則可能會遇到麻煩稍后的。
要考慮的一件好事是您打算如何讓客戶端檢索數據。 如果您打算讓客戶獲取有關許多照片的全部信息,那么僅<photo href="..."/>
可能不是最佳選擇,因為這樣一來,客戶將被迫執行獲取他們需要的有關每個照片資源的GET請求。
我可以想到一些有趣的方法來解決這個問題。
您可以允許客戶端在查詢列表時將其想要檢索的字段指定為查詢參數,例如:
GET http://www.example.com/photos?_fields=author,fileSize
然后,可能返回如下內容:
<photos href="/photos?_fields=author,fileSize">
<photo href="/photos/15">
<author href="/authors/2245"/>
<fileSize>32MB</fileSize>
</photo>
...
</photos>
或者,可以通過允許客戶端指定某種最大的“深度”屬性來簡化操作。 這有點粗糙,但可以有效地使用。 例如,如果客戶端指定深度為2,則將返回<gallery>
下的所有內容以及每個<photo>
所有子元素。
GET /galleries?depth=2
可能會返回類似:
<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>
除此之外,如果您擔心客戶端一次查詢很多條記錄(例如,如果有成千上萬張照片或圖庫),則可能需要考慮對列表進行某種分頁。 這可能涉及為代碼中的結果設置一個硬性最大值,並為客戶端提供指向下一頁/上一頁的鏈接:
GET /photos?gallery=/galleries/59
可能返回:
<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>
客戶端可以控制_first
和_max
性質,但永遠不會增加_max
超過一定配置的閾值。 您將在標記中返回頁面的“找到的”結果數以及可用結果總數。 這將幫助您減少響應大小,您可能會提到此問題。 可以與上面列出的選項同時進行。
最終,這取決於您希望服務器如何指示客戶端檢索數據。 如果您不希望他們為每張照片做一次GET,那么您可能想為他們提供更方便的方法來獲取更深的數據。 但是,如果您認為服務器可以處理適當的負載,並且可以同時進行服務器端優化(緩存,使用304狀態等),則僅返回帶有href
的淺表會更簡單一些。
這確實取決於您的情況。 您需要知道客戶端將如何使用它來了解如何設計資源代理 。
我建議您不要在“選擇十字路口”迷路。 只需根據您對客戶端使用情況的假設進行一個實現即可。 查看整個事物的用法和行為,然后根據需要進行微調。 洗凈,漂洗。 重復。 做永久的Beta版方式:)
您可以隨時使用屬性。
<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>
或者您可以使用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.