HTTP 和 HTTP API 设计
HTTP 基本知識
URI
URL(統(tǒng)一資源定位符),我們比較熟悉,URI是3個單詞的縮寫,Uniform Resource Identifier
URI用字符串表示某一互聯(lián)網(wǎng)資源,而URL表示資源的地點,可見URL是URI的子集;采用HTTP協(xié)議時,協(xié)議方案就是http,除此之外,還有ftp、file等,標(biāo)準(zhǔn)的URI協(xié)議有30種方案左右。
hierarchical part┌───────────────────┴──────────────────┐authority path┌───────────────┴────────────┐┌───┴────┐abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1└┬┘ └───────┬───────┘└────┬────┘└┬┘ └─────────┬───────┘ └──┬──┘ scheme user information host port query fragment 復(fù)制代碼eg:
登錄信息:指定用戶名和密碼作為從服務(wù)器端獲取資源時必要的登錄信息(身份認(rèn)證),可選項。
查詢字符串:針對已指定的文件路徑內(nèi)的資源,可以使用查詢字符串傳入任意參數(shù),可選項。
片段標(biāo)識符:使用片段標(biāo)識符通常可標(biāo)識出已獲取資源中的子資源,可選項。
URI 和 URL 的區(qū)別:
URI 用字符串標(biāo)識某一互聯(lián)網(wǎng)資源,而 URL 標(biāo)識資源的地址
URL 是 URI 的子集
基本規(guī)定
-
發(fā)送規(guī)則
HTTP協(xié)議規(guī)定,請求從客戶端發(fā)出,最后服務(wù)器端響應(yīng)該請求并返回
-
HTTP無狀態(tài)
HTTP是一種不保存狀態(tài),即無狀態(tài)協(xié)議,不會對之前發(fā)送過的請求進行信息的保存
常用HTTP方法
-
GET(SELECT):從服務(wù)器取出資源(一項或多項)
-
POST(CREATE):在服務(wù)器新建一個資源
-
PUT(UPDATE):在服務(wù)器更新資源(客戶端提供改變后的完整資源)
-
PATCH(UPDATE):在服務(wù)器更新資源(客戶端提供改變的屬性)(一般使用PUT)
-
DELETE(DELETE):從服務(wù)器刪除資源
Cookie 狀態(tài)管理
cookie會根據(jù)服務(wù)端發(fā)送的一個叫做Set-Cookie的首部字段信息,通知客服端保存Cookie,當(dāng)下次客服端在往服務(wù)端發(fā)送請求的時候,客服端會自動在請求報文中加入Cookie然后發(fā)送過去,服務(wù)端接收到Cookie之后,對Cookie進行解析,然后找出是哪個用戶。
eg:
一、請求報文(沒有Cookie信息的狀態(tài))
GET /reader/HTTP/1.1 Host:host // 首部字段沒有cookie的相關(guān)信息 復(fù)制代碼二、響應(yīng)報文(服務(wù)器端生成Cookie信息)
HTTP/1.1 200 OK Date:Thu ,12 JUl 2012 07:12:20 GMT Server: Apache <Set-Cookie:sid=1342077140;path=/;expires=wed> Content-Type:text/plain;charset=UTF-8 復(fù)制代碼三、請求報文(自動發(fā)送保存的Cookie信息)
GET /image/ HTTP/1.1 Host host Cookie:sid=1342077140 復(fù)制代碼HTTP報文
結(jié)構(gòu):首部 + 主體
首部
分類:通用首部、請求首部、響應(yīng)首部、實體首部、拓展首部
-
通用首部:客戶端和服務(wù)端都可以用,描述一些通用信息
-
請求首部:請求報文特有,為服務(wù)器提供額外信息
-
響應(yīng)首部:響應(yīng)報文特有,為客戶端提供信息
-
實體首部:描述實體主體部分的首部
-
拓展首部:非標(biāo)準(zhǔn)首部,由應(yīng)用開發(fā)者創(chuàng)建,未添加到HTTP規(guī)范中
通用首部
-
Date:報文創(chuàng)建時間
-
Connection:客戶端和服務(wù)器連接的有關(guān)選項
-
Via:報文經(jīng)過的中間節(jié)點(代理、網(wǎng)關(guān))
-
Cache-control:緩存
請求首部
-
Host:接受請求的服務(wù)器的主機名和端口
-
Referer:當(dāng)前請求的URL
-
UA-OS:客戶端操作系統(tǒng)及版本
-
Accept:告訴服務(wù)器能夠發(fā)送的媒體類型
-
Accept-Charset:告訴服務(wù)器能夠發(fā)送的字符集
-
Accept-Encoding:告訴服務(wù)器能夠發(fā)送的編碼方式
-
Accept-Language:告訴服務(wù)器能夠發(fā)送的語言
-
Authorization:包含客戶端提供給服務(wù)端,以便進行安全認(rèn)證的數(shù)據(jù)
-
Cookie:客戶端需要發(fā)送的cookie
-
Cache-Control: 取值為一般為no-cache或max-age=XX,XX為個整數(shù),表示該資源緩存有效期(秒)
實體首部
-
Allow:對該實體可執(zhí)行的請求方法
-
Location:資源的新地址,重定向中常用到
-
Content-Language:理解主體應(yīng)該使用的語言
-
Content-Length:主體的長度
-
Content-Encoding:對主體實行的編碼方式
-
Content-Type:主體的類型
-
Expires:實體不再有效,需要再次獲取該實體的時間
-
Last-Modified:實體最后一次被修改的時間
響應(yīng)首部
-
Server:服務(wù)器應(yīng)用軟件名稱及版本
-
Set-Cookie:設(shè)置cookie
HTTP 狀態(tài)碼
MDN http status code
MDN http status code -zh-CN
-
1xx 信息響應(yīng)
-
2xx 成功相應(yīng)
-
3xx 重定向
-
4xx 客戶端響應(yīng)
-
5xx 服務(wù)端響應(yīng)
HTTP API 設(shè)計指南
使用 HTTPS
版本化
-
在 URL 中標(biāo)明版本
eg:
http://shonzilla/api/v2.2/customers/1234 http://shonzilla/api/v2.0/customers/1234 http://shonzilla/api/v2/customers/1234 http://shonzilla/api/v1.1/customers/1234 http://shonzilla/api/v1/customers/1234 復(fù)制代碼 -
在 Header 中標(biāo)明版本
-
-
自定義 header
HTTP GET: https://haveibeenpwned.com/api/breachedaccount/foo api-version: 2 復(fù)制代碼
-
-
-
利用 content type
HTTP GET: https://haveibeenpwned.com/api/breachedaccount/foo Accept: application/vnd.haveibeenpwned.v2+json 復(fù)制代碼HTTP GET: https://haveibeenpwned.com/api/breachedaccount/foo Accept: application/vnd.haveibeenpwned+json; version=2.0 復(fù)制代碼
-
返回合適的狀態(tài)碼
為每一次的響應(yīng)返回合適的HTTP狀態(tài)碼. 成功的HTTP響應(yīng)應(yīng)該使用如下的狀態(tài)碼:
-
200: GET請求成功, 以及DELETE或 PATCH 同步請求完成
-
201: POST 同步請求完成
-
202: POST, DELETE, 或 PATCH 異步請求將要完成
-
。。。
對于用戶請求的錯誤情況,及服務(wù)器的異常錯誤情況,請查閱完整的HTTP狀態(tài)碼 HTTP response code spec
在請求的body體使用JSON數(shù)據(jù)
在 PUT/PATCH/POST 請求的body體使用JSON格式數(shù)據(jù), 而不是使用 form 表單形式的數(shù)據(jù). 這里我們使用JSON格式的body請求創(chuàng)建對稱的格式數(shù)據(jù), 例如.:
$ curl -X POST https://service.com/apps \-H "Content-Type: application/json" \-d '{"name": "demoapp"}'{"id": "01234567-89ab-cdef-0123-456789abcdef","name": "demoapp","owner": {"email": "username@example.com","id": "01234567-89ab-cdef-0123-456789abcdef"},... } 復(fù)制代碼提供資源的唯一標(biāo)識
在默認(rèn)情況給每一個資源一個id屬性. 用此作為唯一標(biāo)識除非你有更好的理由不用.不要使用那種在服務(wù)器上或是資源中不是全局唯一的標(biāo)識,比如自動增長的id標(biāo)識。
返回的唯一標(biāo)識要用小寫字母并加個分割線格式 8-4-4-4-12, 例如.:
"id": "01234567-89ab-cdef-0123-456789abcdef" 復(fù)制代碼提供標(biāo)準(zhǔn)的時間戳
提供默認(rèn)的資源創(chuàng)建時間,更新時間 created_at and updated_at , 例如:
{..."created_at": "2012-01-01T12:00:00Z","updated_at": "2012-01-01T13:00:00Z",... } 復(fù)制代碼這些時間戳可能不適用于某些資源,這種情況下可以忽略省去。
使用ISO8601的國際化時間格式
在接收的返回時間數(shù)據(jù)時只使用UTC格式. 查閱ISO8601時間格式, 例如:
"finished_at": "2012-01-01T12:00:00Z" 復(fù)制代碼使用統(tǒng)一的資源路徑
資源命名
使用復(fù)數(shù)形式為資源命名
形為
好的末尾展現(xiàn)形式不許要指定特殊的資源形為,在某些情況下,指定特殊的資源的形為是必須的,用一個標(biāo)準(zhǔn)的actions前綴去替代他, 清楚的描述他:
/resources/:resource/actions/:action 復(fù)制代碼例如.
/runs/{run_id}/actions/stop 復(fù)制代碼路徑和屬性要用小寫字母
使用小寫字母并用-短線分割路徑名字,并且緊跟著主機域名 e.g:
service-api.com/users service-api.com/app-setups 復(fù)制代碼同樣屬性也要用小寫字母, 但是屬性名字要用下劃線_分割。例如.:
"service_class": "first" 復(fù)制代碼嵌套外鍵關(guān)系
序列化的外鍵關(guān)系通常建立在一個有嵌套關(guān)系的對象之上, 例如.:
{"name": "service-production","owner": {"id": "5d8201b0..."},... } 復(fù)制代碼而不是這樣 例如:
{"name": "service-production","owner_id": "5d8201b0...",... } 復(fù)制代碼這種方式盡可能的把相關(guān)聯(lián)的資源信息內(nèi)聯(lián)在一起,而不用改變響應(yīng)資源的結(jié)構(gòu),或者展示更高一級的響應(yīng)區(qū)域, 例如:
{"name": "service-production","owner": {"id": "5d8201b0...","name": "Alice","email": "alice@heroku.com"},... } 復(fù)制代碼支持方便的無id間接引用
在某些情況下,為了方便用戶使用接口,在末尾提供用id標(biāo)識資源,例如,一個用戶想到了他在heroku平臺app的名字,但是這個app的唯一標(biāo)識是id,這種情況下,你想讓接口通過名字和id都能訪問,例如:
$ curl https://service.com/apps/{app_id_or_name} $ curl https://service.com/apps/97addcf0-c182 $ curl https://service.com/apps/www-prod 復(fù)制代碼不要只接受使用名字而剔除了使用id。
構(gòu)建錯誤信息
在網(wǎng)絡(luò)請求響應(yīng)錯誤的時候,返回統(tǒng)一的,結(jié)構(gòu)化的錯誤信息。要包含一個機器可讀的錯誤 id,一個人類能識別的錯誤信息 message, 根據(jù)情況可以添加一個url ,告訴客戶端關(guān)于這個錯誤的更多信息以及如何去解決它。 例如:
HTTP/1.1 429 Too Many Requests 復(fù)制代碼{"id": "rate_limit","message": "Account reached its API rate limit.","url": "https://docs.service.com/rate-limits" } 復(fù)制代碼把你的錯誤信息格式文檔化,以及這些可能的錯誤信息ids 讓客戶端能獲取到.
用id來跟蹤每次的請求
在每一個API響應(yīng)中要包含一個Request-Id頭信息, 通常用唯一標(biāo)識UUID. 如果服務(wù)器和客戶端都打印出他們的Request-Id, 這對我們的網(wǎng)絡(luò)請求調(diào)試和跟蹤非常有幫助.
按范圍分頁
對于服務(wù)器響應(yīng)的大量數(shù)據(jù)我們應(yīng)該為此分頁。 使用Content-Range 頭傳遞分頁請求的數(shù)據(jù).這里有個例子詳細(xì)的說明了請求和響應(yīng)頭、狀態(tài)碼,限制條件、排序以及分頁處理:Heroku Platform API on Ranges.
注:服務(wù)器會在響應(yīng)頭中添加 Accept-Ranges: bytes 來表示支持 Range 的請求,之后客戶端才可能發(fā)起帶 Range 的請求
eg:
# first Content-Length:1200 Content-Range:bytes 0-1199/5000# second Content-Length:1200 Content-Range:bytes 1200-2399/5000# third Content-Length:1200 Content-Range:bytes 2400-3599/5000# fourth Content-Length:1400 Content-Range:bytes 3600-5000/5000 復(fù)制代碼顯示速度限制狀態(tài)
客戶端的訪問速度限制可以維護服務(wù)器的良好狀態(tài),進而為其他客戶端請求提供高性的服務(wù)
為每一個帶有 RateLimit-Remaining 響應(yīng)頭的請求,返回預(yù)留的請求tokens。
指定可接受頭信息的版本
在開始的時候指定API版本,使用Accepts頭傳遞版本信息,也可以是一個自定義的內(nèi)容, 例如:
Accept: application/vnd.heroku+json; version=3 復(fù)制代碼最好不要給出一個默認(rèn)的版本, 而是要求客戶端明確指明他們要使用特定的版本.
提供人類可讀的文檔
提供人類可讀的文檔讓客戶端開發(fā)人員可以理解你的API。
除此之在詳細(xì)信息的結(jié)尾,提供一個關(guān)于如下信息的API摘要:
-
驗證授權(quán),包含獲取及使用驗證tokens.
-
API 穩(wěn)定性及版本控制, 包含如何選擇所需要的版本.
-
一般的請求和響應(yīng)頭信息.
-
錯誤信息序列格式.
-
不同語言客戶端使用API的例子.
提供可執(zhí)行的示例
提供可執(zhí)行的示例讓用戶可以直接在終端里面看到API的調(diào)用情況,最大程度的讓這些示例可以逐字的使用,以減少用戶嘗試使用API的工作量。例如:
$ export TOKEN=... # acquire from dashboard $ curl -is https://$TOKEN@service.com/users 復(fù)制代碼轉(zhuǎn)載于:https://juejin.im/post/5cfa1f2751882575f333f614
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的HTTP 和 HTTP API 设计的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode每日一题:N叉树的层序遍
- 下一篇: Java序列化,看这篇就够了!