哇,所以這個答案迅速升級...
在過去一年左右的時間我已經嘗試通過書籍,郵件列表等出於某種原因,我決定,以獲得更好地瞭解REST的選擇你的問題作爲我所學到的東西的測試。
對不起:P
讓我們把這個整個例子一步簡單。不用擔心用戶上傳文件,我們會假設用戶只是傳遞一個字符串。所以,實際上,除了要替換的字符參數(鍵/值列表)外,他們還要傳遞一個字符串。稍後我們將處理文件上傳部分。
這是一個RESTful的方式,它不需要任何東西存儲在服務器上。我將使用一些HTML(儘管破碎,我會忽略像HEAD這樣的東西)作爲我的媒體類型,只是因爲它是相當知名的。
樣本解決方案
首先,用戶需要訪問我們的REST服務。
GET/
<body>
<a rel="http://example.com/rels/arguments" href="/arguments">
Start Building Arguments
</a>
</body>
這基本上爲用戶提供了一種方式來真正開始對我們的服務進行交互。現在他們只有一個選項:使用鏈接來構建一組新的參數(最終將用於字符串替換方案中的名稱/值對)。所以用戶去那個鏈接。
GET /參數
<body>
<a rel="self" href="/arguments"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}">
<input id="input_string" name="input_string" />
</form>
</body>
這給我們帶來的 「論據」 資源的實例。請注意,這不是一個JSON或XML文檔,它只返回鍵/值對的普通數據;它是超媒體。它包含控件,引導用戶接下來可以做的事情(有時指的是允許用戶「跟隨他們的鼻子」)。這個特定的URL(「/ arguments」)表示鍵/值對的空列表。如果我願意的話,我可以命名爲「/ empty_arguments」:這是一個例子,爲什麼從URL的角度考慮REST是愚蠢的:它實際上並不重要。
在這個新的HTML,爲用戶提供了他們可以瀏覽到三種不同的資源:
- 他們可以使用到「自我」導航到他們目前在相同的資源。
- 他們可以使用第一種形式導航到一個新資源,該資源表示一個參數列表,並使用它們在表單中指定的其他名稱/值組對。
- 他們可以使用第二種形式提供他們希望最終替換的字符串。
注意:您可能會注意到,第二種形式有一個奇怪的 「行動」 網址:
/arguments?{key}={value}
在這裏,我被騙了:我使用URI Templates。這使我可以指定參數將如何放置到URL上,而不是使用僅使用<input-name>=<input-value>
的默認HTML方案。很顯然,爲了這個工作,用戶不能使用瀏覽器(因爲瀏覽器沒有實現這個功能):他們需要使用理解HTML模板的軟件。當然,我使用HTML作爲示例,您的REST服務可以使用某種支持URI模板規範定義的URI模板的XML。
無論如何,假設用戶想要添加他們的參數。用戶使用第一種形式(例如,用「作者」填寫「鍵」輸入,用「John Doe」填寫「價值」輸入)。這導致...
GET /參數?作者約翰=%20Doe
<body>
<a rel="self" href="/arguments?Author=John%20Doe"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe">
<input id="input_string" name="input_string" />
</form>
</body>
現在這是一個全新的資源。您可以使用單個鍵/值對將它描述爲參數列表(鍵/值對):「作者」/「John Doe」。 HTML與以前幾乎相同,只是有一些變化:
- 「自我」鏈接現在指向當前資源URL(從「/ arguments」更改爲「/ arguments?Author = John%20Doe」
- 第一種形式的「動作」屬性現在有較長的網址,但我們再次使用URI模板,使我們能夠建立一個更大的URI。
- 第二種形式
用戶現在希望要添加一個「Date」參數,所以他們再次提交第一個表單,這次用「Date」鍵和一個值「2003-01-02」 。
GET /參數?作者約翰=%20Doe &日期= 2003-01-02
<body>
<a rel="self" href="/arguments?Author=John%20Doe&Date=2003-01-02"/>
<form rel="http://example.com/rels/arguments" method="get" action="/arguments?Author=John%20Doe&Date=2003-01-02&{key}={value}">
<input id="key" name="key" type="text"/>
<input id="value" name="value" type="text"/>
</form>
<form rel="http://example.com/rels/processed_string" action="/processed_string/{input_string}?Author=John%20Doe">
<input id="input_string" name="input_string" />
</form>
</body>
最後,用戶準備處理他們的字符串,所以他們使用的第二種形式,並填寫「 input_string「變量。這又一次使用URI模板,從而將用戶帶到下一個資源。比方說,該字符串如下:
{Author} wrote some books in {Date}
的結果將是:
GET/processed_string /%7BAuthor%7D +寫+有些+書籍+在+%7BDate%7D作者? = John%20Doe & Date = 2003-01-02
<body>
<a rel="self" href="/processed_string/%7BAuthor%7D+wrote+some+books+in+%7BDate%7D?Author=John%20Doe&Date=2003-01-02">
<span class="results">John Doe wrote some books in 2003-01-02</span>
</body>
PHEW!這是很多工作!但它是(AFAIC)RESTful,並且它滿足了不需要在服務器端實際存儲ANYTHING(包括參數列表或最終想要處理的字符串)的要求。
重要的事情要注意
有一點是這裏重要的是,我不只是在談論的URL。實際上,大部分時間我都在談論HTML。 HTML是超媒體,這是REST中被遺忘的很大一部分。所有那些聲稱他們是「寧靜的」,他們說「在這個URL上使用這些參數進行GET並在這個URL上使用類似這樣的文檔進行POST」的API並沒有實踐REST。羅伊菲爾丁(字面上wrote the book on REST)made this observation himself。
另一件需要注意的事情是,設置參數有點痛苦。在初始GET /到達服務的根目錄(你可以認爲它是「菜單」)之後,你需要再做5個GET調用才能建立你的參數資源來創建四個關鍵字的參數資源/值配對。這可以通過不使用HTML來緩解。例如,我已經在我的例子中使用了URI模板,沒有理由說HTML對REST來說不夠好。使用支持類似於表單的超媒體格式(如XML的一些派生),但能夠指定值的「映射」,您可以一次完成此操作。例如,我們可以使用我們的API能夠理解的「映射」輸入類型是什麼,所以長擴展HTML媒體類型,以允許其他所謂的「映射」輸入型...
的客戶,他們會能夠通過一個GET構建他們的參數資源。
在這一點上,你可能甚至不需要「參數」資源。你可以只直接跳到包含映射和實際字符串「processed_string」資源...
什麼文件上傳?
好吧,所以最初你提到文件上傳,以及如何得到這個,而不需要存儲文件。那麼,基本上,我們可以使用我們現有的示例,但用文件替換最後一步。
在這裏,我們基本上做同樣的事情和以前一樣,除了我們正在上傳文件。需要注意的是,現在我們暗示用戶(通過表單上的「method」屬性)他們應該執行POST而不是GET。請注意,儘管處處聽到POST是非安全的(它可能導致服務器發生更改),但是非冪等操作,沒有任何說它必須是服務器上的更改狀態。
最後,服務器可以返回新文件(甚至更好的辦法是返回一些超媒體或LOCATION標頭,並帶有到新文件的鏈接,但這需要存儲)。
最終評論
這只是一個拿這個具體的例子。雖然我希望你已經獲得某種見解,但我會提醒你接受這個福音。我敢肯定,我曾經說過一些事情並不是真正的「休息」。我計劃發佈這個問題並回答REST-Discuss Mailing List,看看別人對此有何評論。
我希望通過這個來表達一件主要的事情,那就是最簡單的解決方案可能就是使用RPC。畢竟,你最初嘗試使RESTful試圖完成什麼?如果你試圖告訴人們你完成了「REST」,請記住,大量的API聲稱自己是「RESTful」,它們真的只是RPC被名詞而不是動詞所僞裝的URL所僞裝。
如果是因爲您已經聽說了REST的一些好處,以及如何通過使您的API RESTful隱含地獲得這些好處,那麼不幸的事實是,除了URL以外,REST還有更多其他優點,以及您是否對其進行GET或POST 。超媒體扮演着重要角色。
最後,有時您會遇到問題,這意味着您可能會做SEEM非RESTful的事情。也許你需要做一個POST而不是一個GET,因爲這個URI(它有一個理論上無限的存儲量,但有很多技術限制)會變得太長。那麼,你需要做POST。也許
更多資源:
剛剛發現了一個非常尖銳的問題,解決(但不回答)我的問題:http://stackoverflow.com/questions/9010724/rest-and-get-again-這似乎是我的問題的癥結所在 - 爲什麼我們是否應該能夠提供複雜/大型數據作爲GET請求的一部分? – 2012-03-15 20:13:12