那些年,我們一起誤解過的REST

来源:https://www.cnblogs.com/qcloud1001/archive/2018/09/07/9606271.html
-Advertisement-
Play Games

歡迎大家前往 "騰訊雲+社區" ,獲取更多騰訊海量技術實踐乾貨哦~ 本文由 "sammyshen" 發表於 "雲+社區專欄" 最近幾年REST API越來越流行,特別是隨著微服務的概念被廣泛接受和應用,很多Web Service都使用了REST API。 REST是HTTP規範主要編寫者之一的Roy ...


歡迎大家前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~

本文由sammyshen 發表於雲+社區專欄

最近幾年REST API越來越流行,特別是隨著微服務的概念被廣泛接受和應用,很多Web Service都使用了REST API。

REST是HTTP規範主要編寫者之一的Roy Fielding提出的,全稱是Representational State Transfer,中文可以翻譯為表述性狀態轉移。它不是一種架構,而是一種架構風格。REST提出了一組架構約束條件和原則,任何滿足REST約束條件和原則的架構,都稱為RESTful架構。

REST雖然流行,但是從業界應用的效果看,良莠不齊。很多系統只是號稱是REST API,實際上並沒有滿足REST的架構約束條件。這些系統按照自己的理解,採用了類似REST API的部分形式(如用GET/POST/PUT/DELETE進行CURD),但更多的是隨意設計,搞出了REST-RPC式,甚至是RPC式的API。這樣的API,不僅沒體現出REST API的優勢,反而搞成“四不像”,增加了開發維護成本。

如何理解REST

要規範使用RESTful架構,首先要理解什麼是REST。我們可以通過分別理解“表述”“狀態轉移”來理解REST。

1) 表述

表述指的是資源的表示。RESTful架構是基於資源的架構(ROA, Resource-Oriented Architecture),在ROA中,處理的對象都是資源。任何需要被引用的對象,都是資源。資源表現為某個具體的URI。

所謂表述,指的是資源的某種形式的表示,這個表示不一定是所有信息,可以只是關註的部分信息。並且,同一個資源,可以有多個表述。例如,對於一個景點,可以用jpeg照片來表示,也可以用包含位置、介紹等信息的json或xml格式來分別表示。

在REST中,客戶端與伺服器之間的通信,傳輸的都是資源的表述。

2) 狀態轉移

狀態其實應該分為應用狀態和資源狀態。

應用狀態由客戶端保存維護,例如會話狀態等。客戶端通過REST API返回的表述,以及表述中的URI,進行客戶端應用狀態的轉移。

但REST更強調的是資源狀態。資源狀態存儲在伺服器端,客戶端通過REST API,指定請求方法、資源路徑和資源表述(可以包含應用狀態),對資源的狀態進行增刪查改。通過增刪查改,引起資源狀態的改變,稱為狀態轉移。

3) 結論

結合上面兩點,客戶端通過REST API對伺服器端的資源進行增刪查改,引起資源的狀態轉移。而這種轉移是體現在表述上的,所以稱為表述性狀態轉移。

怎樣才算是符合REST架構風格

Roy Fielding在他的論文里通過對一個空架構不斷追加約束條件,從而推導出了REST架構風格。因此,要想符合REST架構風格,則需要滿足對應的約束條件。

imgimage.png

對推導過程感興趣的朋友可以參考Roy Fielding的論文

REST的約束條件有:

  1. 統一介面
  2. 無狀態
  3. 緩存
  4. 客戶端-伺服器
  5. 分層系統
  6. 按需代碼(可選)

其中,統一介面是最直觀、也是應用中偏差最大的地方,下麵會重點講解。其餘各約束條件則簡單講解。

1. 統一介面

統一介面其實體現在多個方面:

  • 資源URI
  • 請求參數
  • 請求方法
  • 返回碼
  • 返回內容
  • ……

1) 資源URI

RESTful架構是基於資源的架構,所操作的一切對象都是資源。因此,需要明確地定位一個資源,而URI技術正好滿足這個需求,所以REST中通過URI來定位資源。

資源是一個對象,所以URI中一般只能包含名詞(一般是複數),不應該包含動詞。當需要定位具體的資源時,URI中一般包含資源的唯一ID。例如:

// 滿足REST架構風格的URI
http://www.example.com/books    // 所有書籍的資源集合
http://www.example.com/books/123    // ID為123的書籍資源

// 不滿足REST架構風格的URI
http://www.example.com/books/query
http://www.example.com/buy

2) 請求參數

因為REST需要通過URI來唯一定位某個(或某種)資源,所以查詢資源時,各種資源ID一般是放在URI裡面,而不是放在請求參數裡面。請求參數中一般放過濾條件分頁信息等欄位。例如:

// 滿足REST架構風格的URI
http://www.example.com/books/123    // ID為123的書籍資源
http://www.example.com/Fielding/books?page=1&per_page=10    // 作者為Fielding的前10本書籍資源集合

// 不滿足REST架構風格的URI
http://www.example.com/books?id=123
http://www.example.com/books?author=Fielding

3) 請求方法

REST約定用GET/POST/PUT/DELETE等請求方法來進行CURD操作。但是否使用了GET/POST/PUT/DELETE,並不能作為評判一個系統是否符合REST架構風格的標準。例如,有些系統所有介面都使用GET和POST方法,如果該系統只提供查詢和創建操作,那麼可能是符合REST架構風格的;但如果該系統還提供修改、刪除操作,則該系統不符合REST架構風格。

有些人認為GET/POST/PUT/DELETE跟CURD是一對一的關係,其實不是。

具體的說,各請求方法如下:

另外,還有其他較少用的請求方法,需要註意的是可能部分瀏覽器不支持。

  • HEAD:用於獲取資源的元信息。HEAD方法與GET方法類似,都可以查詢資源的元信息(放在HTTP Response的Header),但不會返回資源的表述。例如用於判斷資源是否存在。
  • PATCH:用於修改資源。與PUT方法不同的是,PATCH方法只傳輸改動的部分資源表述,而PUT方法需要傳輸完整的資源表述。

4) 返回碼

REST使用HTTP返回碼來表示請求的結果。如果使用規範的REST API,那麼根據HTTP返回碼就能確定很多信息。常見的HTTP返回碼如下:

  • 200(OK):表示請求成功。
  • 201(Created):表示資源創建成功。
  • 204(No content):表示資源為空。
  • 301(Moved Permanently):表示資源的URI已永久性更改,需要在響應內容中獲取新的URI。
  • 302(Moved Temporarily):表示資源的URI已臨時性更改,需要在響應內容中獲取新的URI。
  • 400(Bad Request):表示請求有問題,如參數錯誤等。
  • 403(Forbidden):表示鑒權不通過,沒有許可權訪問該資源。
  • 404(Not Found):表示資源不存在。
  • 405(Method Not Allowed):表示該資源不支持當前的請求方法。
  • 409(Conflict):表示當前請求的某前置條件不符合。
  • 500(Internal Server Error):通用內部錯誤。
  • 502(Bad Gateway):網關錯誤,從上游伺服器收到無效響應。
  • 504(Gateway Timeout):網關超時,在預期時間內沒有收到上游伺服器的響應。
  • ……

還有其他HTTP返回碼,可以參考HTTP標準。

只要使用了規範的REST架構風格,那麼就可以根據HTTP的標準,做出明確的相應處理,無需另外製定私有協議了。既減少了私有協議的相容性問題,又能作為標準適用於所有的RESTful架構。

5) 返回內容

REST API的返回內容應該是資源的表述。

前面說過,同一個資源可以有多種不同格式的表述,如json格式和xml格式,所以返回內容應該是自描述的。也就是說,在HTTP響應的Header中,必須包含Content-type屬性,如application/json、application/xml、text/html等。

另外,REST是“可編程”的Web服務,也就是說,程式可以根據REST API的返回內容,進行下一步的操作。例如,查詢author資源,下一步可能是要查詢該作者著作的book資源。所以,如果author資源的表述中包含了該作者著作book資源的URI,則客戶端可以進行相應的操作。又如,查詢某個地圖資源,地圖資源的表述中如果包含了各方向的相鄰地圖資源,則當客戶端的滑鼠移到屏幕邊緣時,就可以獲取到該方向上的地圖資源了;或者地圖資源的表述中包含景點、餐館等資源URI,則可以進行相應的操作。

在表述中包含其他資源的URI實現了連通性。連通性可以作為客戶端應用狀態的狀態引擎,引導客戶端進行下一步的操作,帶來了極大的便利。

6) 其他

統一介面還有其他方面的原則,本文就不細講了,感興趣的朋友可以閱讀Fielding的論文。

2. 無狀態

無狀態約束條件是指兩次請求之間不存在依賴關係,每一次請求都包含完整的狀態信息。這裡指的狀態是指客戶端與伺服器之間通信交互的狀態,與資源狀態無關。

舉個有狀態的例子,為了查工資,需要先登錄系統(第一次請求),再輸入查詢密碼(第二次請求)。如果前面兩次請求都通過了,那麼調用查詢介面則可以查詢到工資;否則調用查詢介面則報未鑒權的錯誤。查詢工資介面的返回結果與前面兩次請求的狀態是關聯的,所以是有狀態的服務。

而無狀態的服務,則直接調用查詢工資介面,在請求中(一般在Header中)帶有鑒權信息,若鑒權通過則可查詢到工資,鑒權不通過則報錯。該請求不依賴於任何前置請求,稱為無狀態。

REST使用無狀態約束條件,確保了請求的獨立性和簡單性,減少了很多跨請求的狀態維護成本。當然,帶來的代價是每次請求可能需要傳輸冗餘的信息。

3. 緩存

緩存約束條件主要是用於改善網路的效率。緩存約束條件要求一個請求的響應中的數據被隱式地或顯式地標記為可緩存的或不可緩存的。如果響應是可緩存的,那麼客戶端緩存就可以為以後的相同請求重用這個響應的數據,減少了網路交互,提高了效率、可伸縮性和用戶感知的性能。

4. 客戶端-伺服器

這個約束條件主要是分離用戶界面和數據存儲,一方面改善用戶界面跨平臺的可移植性,另一方面簡化伺服器組件,改善系統的可伸縮性。

5. 分層系統

分層系統架構約束條件將架構分為若幹層,劃定每一層的邊界,從而降低每一層設計的複雜度。同時,通過分層,可以抽象底層的異構性,給上層提供統一的介面,簡化上層的邏輯。

6. 按需代碼

按需代碼約束條件是指某些場景下,客戶端不清楚資源的處理方法,通過向伺服器請求相應的處理代碼來執行。這樣可以簡化客戶端開發,允許部署後下載功能代碼來改善系統的可擴展性。但是,因為傳輸的是代買,降低了可見性,所以是REST的一個可選的架構約束條件。

問答
Java中的REST
相關閱讀
體驗Django REST framework,解讀REST架構風格
我是怎麼一步步用go找出壓測性能瓶頸
當 MySQL 連接池遇上事務(一):神秘的幽靈鎖
【每日課程推薦】機器學習實戰!快速入門線上廣告業務及CTR相應知識

此文已由作者授權騰訊雲+社區發佈,更多原文請點擊

搜索關註公眾號「雲加社區」,第一時間獲取技術乾貨,關註後回覆1024 送你一份技術課程大禮包!

海量技術實踐經驗,盡在雲加社區


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • CSS的四種引用方式: 1、行內樣式、內聯樣式 2、內嵌樣式、內部樣式 3、鏈接樣式 4、導入樣式 行內樣式 、內聯樣式 行內樣式是最簡單的一種css(Cascading Style Sheets【層疊樣式表】)使用方式,就是在html標簽中使用style屬性添加CSS樣式。 例如: <p styl ...
  • 近期已朋友問我問題,實現類似淘寶百度的下啦搜索條,看了網上好多帖子,都看起來好複雜,而且引用了好多沒用的東西,而且多選選擇內容多之後容易樣式奔潰, 無奈之下只好自己改了, 話不多說上效果圖: 模糊搜索廣會自動補全所有帶廣的下拉選項.每個選中的可以單獨刪除. 大神勿噴,給需要的朋友個幫助,話不多說,上 ...
  • 一、安裝NPM 1.1最新穩定版本: npm install vue 二、命令行工具安裝 國內速度慢,使用淘寶鏡像: npm install -g cnpm --registry=https://registry.npm.taobao.org 註意:以後使用npm的地方就替換成cnpm 1、全局安裝 ...
  • Angular新建項目步驟記錄 標簽(空格分隔): Angular 1. 2. 啟動dev環境 3. 修改 為`styles.scss`,同時修改文件 .angular cli.json 中的: 重新打包。 4. 配置全局樣式 /src 目錄下添加 文件夾 /scss 目錄下添加 ,`./utili ...
  • 一、初始JavaScript 二、瀏覽器的組成 2008年Google發佈了Chrome,它是採用優化後的js引擎,引擎代號V8,因能把js代碼直接轉化成機械碼0101來執行,進而以速度快而聞名。 ...
  • ( ′◔ ‸◔`)現在的公司啊都流行混合開發,我們公司也不例外,非要把交互非常多的社區模塊用內嵌web頁展示,好吧好吧,畢竟有的應用也是這麼做的,那既然是社區就肯定少不了用戶上傳圖片的操作,在開發階段沒有發現任何問題,也是很奇怪,等到了測試階段,發現部分機型和IOS機型拍照之後,web頁獲取路徑之後 ...
  • 在前後端分離的項目中,通常需要啟動一個後臺伺服器來配合前端項目的介面需求。Mockjs的作用是攔截ajax請求並模擬各種數據返回,讓前端開發可以更加自由獨立。 安裝 使用 Mock.mock()第一個參數是需要攔截的介面,第二個參數表明ajax請求類型(get/post/put/delete等),第 ...
  • 將多個系統的登陸認證步驟集中在登陸系統統一管理,用戶只需要登陸一次就可以在多個系統之間來回切換使用 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...