1. 程式人生 > >【RESTful】理解RESTful架構

【RESTful】理解RESTful架構

                                        

越來越多的人開始意識到,網站即軟體,而且是一種新型的軟體。

                                                                             

這種"網際網路軟體"採用客戶端/伺服器模式,建立在分散式體系上,通過網際網路通訊,具有高延時(high latency)、高併發等特點。

網站開發,完全可以採用軟體開發的模式。但是傳統上,軟體和網路是兩個不同的領域,很少有交集;軟體開發主要針對單機環境,網路則主要研究系統之間的通訊。網際網路的興起,使得這兩個領域開始融合,現在我們必須考慮,如何開發在網際網路環境中使用的軟體。

RESTful架構,就是目前最流行的一種網際網路軟體架構。它結構清晰、符合標準、易於理解、擴充套件方便,所以正得到越來越多網站的採用。

但是,到底什麼是RESTful架構,並不是一個容易說清楚的問題。下面,我就談談我理解的RESTful架構。

一、起源

REST這個詞,是Roy Thomas Fielding在他2000年的博士論文中提出的。

Fielding是一個非常重要的人,他是HTTP協議(1.0版和1.1版)的主要設計者、Apache伺服器軟體的作者之一、Apache基金會的第一任主席。所以,他的這篇論文一經發表,就引起了關注,並且立即對網際網路開發產生了深遠的影響。

他這樣介紹論文的寫作目的:

"本文研究電腦科學兩大前沿----軟體和網路----的交叉點。長期以來,軟體研究主要關注軟體設計的分類、設計方法的演化,很少客觀地評估不同的設計選擇對系統行為的影響。而相反地,網路研究主要關注系統之間通訊行為的細節、如何改進特定通訊機制的表現,常常忽視了一個事實,那就是改變應用程式的互動風格比改變互動協議,對整體表現有更大的影響。我這篇文章的寫作目的,就是想在符合架構原理的前提下,理解和評估以網路為基礎的應用軟體的架構設計,得到一個功能強、效能好、適宜通訊的架構。

"

(This dissertation explores a junction on the frontiers of two research disciplines in computer science: software and networking. Software research has long been concerned with the categorization of software designs and the development of design methodologies, but has rarely been able to objectively evaluate the impact of various design choices on system behavior. Networking research, in contrast, is focused on the details of generic communication behavior between systems and improving the performance of particular communication techniques, often ignoring the fact that changing the interaction style of an application can have more impact on performance than the communication protocols used for that interaction. My work is motivated by the desire to understand and evaluate the architectural design of network-based application software through principled use of architectural constraints, thereby obtaining the functional, performance, and social properties desired of an architecture. )

二、名稱

Fielding將他對網際網路軟體的架構原則,定名為REST,即Representational State Transfer的縮寫。我對這個片語的翻譯是"表現層狀態轉化"。

如果一個架構符合REST原則,就稱它為RESTful架構。

要理解RESTful架構,最好的方法就是去理解Representational State Transfer這個片語到底是什麼意思,它的每一個詞代表了什麼涵義。如果你把這個名稱搞懂了,也就不難體會REST是一種什麼樣的設計。

三、資源(Resources)

REST的名稱"表現層狀態轉化"中,省略了主語。"表現層"其實指的是"資源"(Resources)的"表現層"。

所謂"資源",就是網路上的一個實體,或者說是網路上的一個具體資訊。它可以是一段文字、一張圖片、一首歌曲、一種服務,總之就是一個具體的實在。你可以用一個URI(統一資源定位符)指向它,每種資源對應一個特定的URI。要獲取這個資源,訪問它的URI就可以,因此URI就成了每一個資源的地址或獨一無二的識別符。

所謂"上網",就是與網際網路上一系列的"資源"互動,呼叫它的URI。

四、表現層(Representation)

"資源"是一種資訊實體,它可以有多種外在表現形式。我們把"資源"具體呈現出來的形式,叫做它的"表現層"(Representation)。

比如,文字可以用txt格式表現,也可以用HTML格式、XML格式、JSON格式表現,甚至可以採用二進位制格式;圖片可以用JPG格式表現,也可以用PNG格式表現。

URI只代表資源的實體,不代表它的形式。嚴格地說,有些網址最後的".html"字尾名是不必要的,因為這個字尾名錶示格式,屬於"表現層"範疇,而URI應該只代表"資源"的位置。它的具體表現形式,應該在HTTP請求的頭資訊中用Accept和Content-Type欄位指定,這兩個欄位才是對"表現層"的描述。

五、狀態轉化(State Transfer)

訪問一個網站,就代表了客戶端和伺服器的一個互動過程。在這個過程中,勢必涉及到資料和狀態的變化。

網際網路通訊協議HTTP協議,是一個無狀態協議。這意味著,所有的狀態都儲存在伺服器端。因此,如果客戶端想要操作伺服器,必須通過某種手段,讓伺服器端發生"狀態轉化"(State Transfer)。而這種轉化是建立在表現層之上的,所以就是"表現層狀態轉化"。

客戶端用到的手段,只能是HTTP協議。具體來說,就是HTTP協議裡面,四個表示操作方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操作:GET用來獲取資源,POST用來新建資源(也可以用於更新資源),PUT用來更新資源,DELETE用來刪除資源。

六、綜述

綜合上面的解釋,我們總結一下什麼是RESTful架構:

  (1)每一個URI代表一種資源;

  (2)客戶端和伺服器之間,傳遞這種資源的某種表現層;

  (3)客戶端通過四個HTTP動詞,對伺服器端資源進行操作,實現"表現層狀態轉化"。

七、誤區

RESTful架構有一些典型的設計誤區。

最常見的一種設計錯誤,就是URI包含動詞。因為"資源"表示一種實體,所以應該是名詞,URI不應該有動詞,動詞應該放在HTTP協議中。

舉例來說,某個URI是/posts/show/1,其中show是動詞,這個URI就設計錯了,正確的寫法應該是/posts/1,然後用GET方法表示show。

如果某些動作是HTTP動詞表示不了的,你就應該把動作做成一種資源。比如網上匯款,從賬戶1向賬戶2匯款500元,錯誤的URI是:

  POST /accounts/1/transfer/500/to/2

正確的寫法是把動詞transfer改成名詞transaction,資源不能是動詞,但是可以是一種服務:

  POST /transaction HTTP/1.1
  Host: 127.0.0.1
  
  from=1&to=2&amount=500.00

另一個設計誤區,就是在URI中加入版本號

  http://www.example.com/app/1.0/foo

  http://www.example.com/app/1.1/foo

  http://www.example.com/app/2.0/foo

因為不同的版本,可以理解成同一種資源的不同表現形式,所以應該採用同一個URI。版本號可以在HTTP請求頭資訊的Accept欄位中進行區分(參見Versioning REST Services):

  Accept: vnd.example-com.foo+json; version=1.0

  Accept: vnd.example-com.foo+json; version=1.1

  Accept: vnd.example-com.foo+json; version=2.0

RESTful API 設計指南

                                        

網路應用程式,分為前端和後端兩個部分。當前的發展趨勢,就是前端裝置層出不窮(手機、平板、桌面電腦、其他專用裝置......)。

                                                                             

因此,必須有一種統一的機制,方便不同的前端裝置與後端進行通訊。這導致API構架的流行,甚至出現"API First"的設計思想。RESTful API是目前比較成熟的一套網際網路應用程式的API設計理論。我以前寫過一篇《理解RESTful架構》,探討如何理解這個概念。

今天,我將介紹RESTful API的設計細節,探討如何設計一套合理、好用的API。我的主要參考資料是這篇《Principles of good RESTful API Design》

RESTful API

一、協議

API與使用者的通訊協議,總是使用HTTPs協議

二、域名

應該儘量將API部署在專用域名之下。


https://api.example.com

如果確定API很簡單,不會有進一步擴充套件,可以考慮放在主域名下。


https://example.org/api/

三、版本(Versioning)

應該將API的版本號放入URL。


https://api.example.com/v1/

另一種做法是,將版本號放在HTTP頭資訊中,但不如放入URL方便和直觀。

四、路徑(Endpoint)

路徑又稱"終點"(endpoint),表示API的具體網址。

在RESTful架構中,每個網址代表一種資源(resource),所以網址中不能有動詞,只能有名詞,而且所用的名詞往往與資料庫的表格名對應。一般來說,資料庫中的表都是同種記錄的"集合"(collection),所以API中的名詞也應該使用複數。

舉例來說,有一個API提供動物園(zoo)的資訊,還包括各種動物和僱員的資訊,則它的路徑應該設計成下面這樣。

  • https://api.example.com/v1/zoos
  • https://api.example.com/v1/animals
  • https://api.example.com/v1/employees

五、HTTP動詞

對於資源的具體操作型別,由HTTP動詞表示。

常用的HTTP動詞有下面五個(括號裡是對應的SQL命令)。

  • GET(SELECT):從伺服器取出資源(一項或多項)。
  • POST(CREATE):在伺服器新建一個資源。
  • PUT(UPDATE):在伺服器更新資源(客戶端提供改變後的完整資源)。
  • PATCH(UPDATE):在伺服器更新資源(客戶端提供改變的屬性)。
  • DELETE(DELETE):從伺服器刪除資源。

還有兩個不常用的HTTP動詞。

  • HEAD:獲取資源的元資料。
  • OPTIONS:獲取資訊,關於資源的哪些屬性是客戶端可以改變的。

下面是一些例子。

  • GET /zoos:列出所有動物園
  • POST /zoos:新建一個動物園
  • GET /zoos/ID:獲取某個指定動物園的資訊
  • PUT /zoos/ID:更新某個指定動物園的資訊(提供該動物園的全部資訊)
  • PATCH /zoos/ID:更新某個指定動物園的資訊(提供該動物園的部分資訊)
  • DELETE /zoos/ID:刪除某個動物園
  • GET /zoos/ID/animals:列出某個指定動物園的所有動物
  • DELETE /zoos/ID/animals/ID:刪除某個指定動物園的指定動物

六、過濾資訊(Filtering)

如果記錄數量很多,伺服器不可能都將它們返回給使用者。API應該提供引數,過濾返回結果。

下面是一些常見的引數。

  • ?limit=10:指定返回記錄的數量
  • ?offset=10:指定返回記錄的開始位置。
  • ?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序。
  • ?animal_type_id=1:指定篩選條件

引數的設計允許存在冗餘,即允許API路徑和URL引數偶爾有重複。比如,GET /zoo/ID/animals 與 GET /animals?zoo_id=ID 的含義是相同的。

七、狀態碼(Status Codes)

伺服器向用戶返回的狀態碼和提示資訊,常見的有以下一些(方括號中是該狀態碼對應的HTTP動詞)。

  • 200 OK - [GET]:伺服器成功返回使用者請求的資料,該操作是冪等的(Idempotent)。
  • 201 CREATED - [POST/PUT/PATCH]:使用者新建或修改資料成功。
  • 204 NO CONTENT - [DELETE]:使用者刪除資料成功。
  • 400 INVALID REQUEST - [POST/PUT/PATCH]:使用者發出的請求有錯誤,伺服器沒有進行新建或修改資料的操作,該操作是冪等的。。
  • 404 NOT FOUND - [*]:使用者發出的請求針對的是不存在的記錄,伺服器沒有進行操作,該操作是冪等的。
  • 500 INTERNAL SERVER ERROR - [*]:伺服器發生錯誤,使用者將無法判斷髮出的請求是否成功。

狀態碼的完全列表參見這裡

八、錯誤處理(Error handling)

如果狀態碼是4xx,就應該向使用者返回出錯資訊。一般來說,返回的資訊中將error作為鍵名,出錯資訊作為鍵值即可。


{
    error: "Invalid API key"
}

九、返回結果

針對不同操作,伺服器向用戶返回的結果應該符合以下規範。

  • GET /collection:返回資源物件的列表(陣列)
  • GET /collection/resource:返回單個資源物件
  • POST /collection:返回新生成的資源物件
  • PUT /collection/resource:返回完整的資源物件
  • PATCH /collection/resource:返回完整的資源物件
  • DELETE /collection/resource:返回一個空文件

十、Hypermedia API

RESTful API最好做到Hypermedia,即返回結果中提供連結,連向其他API方法,使得使用者不查文件,也知道下一步應該做什麼。

比如,當用戶向api.example.com的根目錄發出請求,會得到這樣一個文件。


{"link": {
  "rel":   ,
  "href":  ,
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

上面程式碼表示,文件中有一個link屬性,使用者讀取這個屬性就知道下一步該呼叫什麼API了。rel表示這個API與當前網址的關係(collection關係,並給出該collection的網址),href表示API的路徑,title表示API的標題,type表示返回型別。

Hypermedia API的設計被稱為HATEOAS。Github的API就是這種設計,訪問api.github.com會得到一個所有可用API的網址列表。

從上面可以看到,如果想獲取當前使用者的資訊,應該去訪問api.github.com/user,然後就得到了下面結果。


{
  "message": "Requires authentication",
  "documentation_url": 
}

上面程式碼表示,伺服器給出了提示資訊,以及文件的網址。

十一、其他

(1)API的身份認證應該使用OAuth 2.0框架。

(2)伺服器返回的資料格式,應該儘量使用JSON,避免使用XML。

相關推薦

RESTful理解RESTful架構

                                         越來越多的人開始意識到,網站即軟體,而且是一種新型的軟體。                                                                               這種"網際網

flaskflask-restful和jsonify編碼問題

在做web開發的時候經常會遇到返回中文字串的問題,到瀏覽器中就會被轉碼,因此記錄下解決方法。 程式碼如下: @bp.route('/logout') def logout(): if 'user_uid' in session: session.pop('user_u

ShiroApache Shiro架構之身份認證(Authentication)

trac pretty asm 安全保障 軟件測試 釋放 model tac 讀取配置文件 Shiro系列文章: 【Shiro】Apache Shiro架構之權限認證(Authorization) 【Shiro】Apache Shiro架構之集成web

理解Callable 和 Spring DeferredResult

控制 defer -a word int https .html getc when http://www.cnblogs.com/aheizi/p/5659030.html 1-介紹 Servlet 3中的異步支持為在另一個線程中處理HTTP請求提供了可能性。當

軟件架構設計-五視圖方法論

存儲 文檔 ieee 不同 配置 網站 源文件 sha 領域 1.每個人都可以做成為架構設計師 不懂軟件的和剛入行的人們一聽到架構設計,都認為是非常的高大上課題,是一個遙不可及的領域,一般人是不能做的。聽起來雲裏霧裏的,第一印象除了來自微軟,阿裏這些NB的公司裏

互聯網架構的三板斧

這一 dba 完全 hashmap 普通 eight 中介 keys res 轉自:https://yq.aliyun.com/articles/54449 測試輩的也學習學習~~ 對架構還是甚是感興趣的 對好的架構方法論及實踐能信手拈來 我要成為真正的高手

文摘理解矩陣

包含 就是 所有 %d 裏的 界定 運用 表示 提高 文摘自 某人筆記 理解矩陣(忘了在哪看到的,直接復制下來的,剛剛看過一遍覺得對高等代數有了一個全新的理解) 線性代數課程,無論你從行列式入手還是直接從矩陣入手,從一開始就充斥著莫名其妙。比如說,在全國一般工科院系教學中應

譯文理解storm拓撲並行度

rec 分享 矩形 bolt pos div pro out data 原文地址: http://storm.apache.org/releases/1.2.1/Understanding-the-parallelism-of-a-Storm-topology.html 什

理解WebKit和Chromium: JavaScript引擎簡介

正則表達 根據 tco 抽象 由於 介紹 後來 rom 都在 轉載請註明原文地址:http://blog.csdn.net/milado_nju1. 什麽是JavaScript引擎什麽是JavaScript引擎?簡單來講,就是能夠提供執行JavaScript代碼的運行環境。

Python理解yield和generator(生成器)

Overview 本文整理自: [1] Python yield 使用淺析 —— 廖雪峰 [2] 深入理解yield —— Python中文開發者社群 如何生成斐波那契數列 斐波那契(Fibonacci)數列是一個非常簡單的遞迴數列,除第一個和第二個數外,任意一個數都可由前兩

理解 Javascript 執行上下文和執行棧

原文地址:Understanding Execution Context and Execution Stack in Javascript 譯文地址:理解 Javascript 執行上下文和執行棧 譯者:夏佳昊 校對

slighttpd基於lighttpd架構的Server專案實戰(4)—簡單的echo伺服器

轉載地址:https://blog.csdn.net/jiange_zh/article/details/50636536 在這一部分,我們將對上一篇中的master-worker進行拓展,成為一個簡單的echo伺服器。 這一步我們需要新增兩個類:Listener和Connection;

slighttpd基於lighttpd架構的Server專案實戰(3)—Master&Worker模式

轉載地址:https://blog.csdn.net/jiange_zh/article/details/50636180 現在,我們開始一步步構建我們的專案了~ Master-Worker模式 本次一共涉及2個類:Master和Worker; 以下是兩者的標頭檔案: /****

slighttpd基於lighttpd架構的Server專案實戰(2)—預備知識之libevent

轉載地址:https://blog.csdn.net/jiange_zh/article/details/50631393 簡介 由於本專案是純非同步的,而對於大量 socket 連線,使用 select 並不高效。(參見我的另一篇博文:epoll簡介) 事實上,大部分系統提供了處理大

slighttpd基於lighttpd架構的Server專案實戰(7)—http-parser

轉載地址:https://blog.csdn.net/jiange_zh/article/details/50639178 對於http伺服器,http request的解析是比較麻煩的,由於我們的重點並不在這上面,所以這一部分不打算自己編寫,而是使用開源的http-parser庫,下面我們將使

slighttpd基於lighttpd架構的Server專案實戰(8)—狀態機機制回顧

轉載地址:https://blog.csdn.net/jiange_zh/article/details/50640270 有限狀態機FSM(Finite State Machine) 關於狀態機的一個極度確切的描述是它是一個有向圖形,由一組節點和一組相應的轉移函式組成。狀態機通過響應一系列

slighttpd基於lighttpd架構的Server專案實戰(5)—TCP的TIME_WAIT狀態

轉載地址:https://blog.csdn.net/jiange_zh/article/details/50637549 上一節我們已經開發了一個簡單的echo伺服器,在這裡我們先不急著繼續下去,先看看一些小細節! 在listener的程式碼中,對於監聽套接字,我設定了SO_REUSEAD

理解 JavaScript 中的 undefined

原文地址:Understanding JavaScript’s ‘undefined’ 原文作者:Angus Croll 譯文出自:掘金翻譯計劃 本文永久連結:github.com/xitu/gold-m… 譯者:yanyixin 校對者:noahziheng, M

理解JavaScript閉包——新手指南

閉包是JavaScript中一個基本的概念,每個JavaScript開發者都應該知道和理解的。然而,很多新手JavaScript開發者對這個概念還是很困惑的。 正確理解閉包可以幫助你寫出更好、更高效、簡潔的程式碼。同時,這將會幫助你成為更好的JavaScript開發者。 因此,在這篇文章中,我將會嘗試解析

理解JMX之介紹和簡單使用

原文連結:https://blog.csdn.net/lmy86263/article/details/71037316  近期在專案上需要新增一些功能,想把一個開源工程整合進來,雖說是整合,但是覺得跟開發有查不了多少,要讓這個開源工程的編碼風格和設計方式與我們的工程保持一