HTTP 和 HTTP API 設計

HTTP 基本知識

URI

URL(統一資源定位符),咱們比較熟悉,URI是3個單詞的縮寫,Uniform Resource Identifierhtml

URI用字符串表示某一互聯網資源,而URL表示資源的地點,可見URL是URI的子集;採用HTTP協議時,協議方案就是http,除此以外,還有ftp、file等,標準的URI協議有30種方案左右。json

hierarchical part
        ┌───────────────────┴──────────────────┐
                    authority               path
        ┌───────────────┴────────────┐┌───┴────┐
  abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
  └┬┘  └───────┬───────┘└────┬────┘└┬┘           └─────────┬───────┘ └──┬──┘
scheme  user information     host     port                  query         fragment
複製代碼

eg:api

img

登陸信息:指定用戶名和密碼做爲從服務器端獲取資源時必要的登陸信息(身份認證),可選項。緩存

查詢字符串:針對已指定的文件路徑內的資源,可使用查詢字符串傳入任意參數,可選項。安全

片斷標識符:使用片斷標識符一般可標識出已獲取資源中的子資源,可選項。bash

URI 和 URL 的區別:服務器

URI 用字符串標識某一互聯網資源,而 URL 標識資源的地址cookie

URL 是 URI 的子集網絡

基本規定

  • 發送規則app

    HTTP協議規定,請求從客戶端發出,最後服務器端響應該請求並返回

  • HTTP無狀態

    HTTP是一種不保存狀態,即無狀態協議,不會對以前發送過的請求進行信息的保存

經常使用HTTP方法

  • GET(SELECT):從服務器取出資源(一項或多項)

  • POST(CREATE):在服務器新建一個資源

  • PUT(UPDATE):在服務器更新資源(客戶端提供改變後的完整資源)

  • PATCH(UPDATE):在服務器更新資源(客戶端提供改變的屬性)(通常使用PUT)

  • DELETE(DELETE):從服務器刪除資源

Cookie 狀態管理

cookie會根據服務端發送的一個叫作Set-Cookie的首部字段信息,通知客服端保存Cookie,當下次客服端在往服務端發送請求的時候,客服端會自動在請求報文中加入Cookie而後發送過去,服務端接收到Cookie以後,對Cookie進行解析,而後找出是哪一個用戶。

eg:

1、請求報文(沒有Cookie信息的狀態)

GET /reader/HTTP/1.1
Host:host
// 首部字段沒有cookie的相關信息
複製代碼

2、響應報文(服務器端生成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
複製代碼

3、請求報文(自動發送保存的Cookie信息)

GET /image/ HTTP/1.1
Host host
Cookie:sid=1342077140
複製代碼

HTTP報文

結構:首部 + 主體

img

img

img

首部

分類:通用首部、請求首部、響應首部、實體首部、拓展首部

  • 通用首部:客戶端和服務端均可以用,描述一些通用信息

  • 請求首部:請求報文特有,爲服務器提供額外信息

  • 響應首部:響應報文特有,爲客戶端提供信息

  • 實體首部:描述實體主體部分的首部

  • 拓展首部:非標準首部,由應用開發者建立,未添加到HTTP規範中

通用首部

  • Date:報文建立時間

  • Connection:客戶端和服務器鏈接的有關選項

  • Via:報文通過的中間節點(代理、網關)

  • Cache-control:緩存

請求首部

  • Host:接受請求的服務器的主機名和端口

  • Referer:當前請求的URL

  • UA-OS:客戶端操做系統及版本

  • Accept:告訴服務器可以發送的媒體類型

  • Accept-Charset:告訴服務器可以發送的字符集

  • Accept-Encoding:告訴服務器可以發送的編碼方式

  • Accept-Language:告訴服務器可以發送的語言

  • Authorization:包含客戶端提供給服務端,以便進行安全認證的數據

  • Cookie:客戶端須要發送的cookie

  • Cache-Control: 取值爲通常爲no-cachemax-age=XX,XX爲個整數,表示該資源緩存有效期(秒)

實體首部

  • Allow:對該實體可執行的請求方法

  • Location:資源的新地址,重定向中經常使用到

  • Content-Language:理解主體應該使用的語言

  • Content-Length:主體的長度

  • Content-Encoding:對主體實行的編碼方式

  • Content-Type:主體的類型

  • Expires:實體再也不有效,須要再次獲取該實體的時間

  • Last-Modified:實體最後一次被修改的時間

響應首部

  • Server:服務器應用軟件名稱及版本

  • Set-Cookie:設置cookie

HTTP 狀態碼

MDN http status code

MDN http status code -zh-CN

  • 1xx 信息響應

  • 2xx 成功相應

  • 3xx 重定向

  • 4xx 客戶端響應

  • 5xx 服務端響應

HTTP API 設計指南

使用 HTTPS

版本化

  • 在 URL 中標明版本

    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
    複製代碼
  • 在 Header 中標明版本

    • 自定義 header

      HTTP GET:
      https://haveibeenpwned.com/api/breachedaccount/foo
      api-version: 2
      複製代碼
    • 利用 content type

      HTTP GET:
      https://haveibeenpwned.com/api/breachedaccount/foo
      Accept: application/vnd.haveibeenpwned.v2+json
      複製代碼
      HTTP GET:
      https://haveibeenpwned.com/api/breachedaccount/foo
      Accept: application/vnd.haveibeenpwned+json; version=2.0
      複製代碼

返回合適的狀態碼

爲每一次的響應返回合適的HTTP狀態碼. 成功的HTTP響應應該使用以下的狀態碼:

  • 200: GET請求成功, 以及DELETEPATCH 同步請求完成

  • 201: POST 同步請求完成

  • 202: POST, DELETE, 或 PATCH 異步請求將要完成

  • 。。。

對於用戶請求的錯誤狀況,及服務器的異常錯誤狀況,請查閱完整的HTTP狀態碼 HTTP response code spec

在請求的body體使用JSON數據

PUT/PATCH/POST 請求的body體使用JSON格式數據, 而不是使用 form 表單形式的數據. 這裏咱們使用JSON格式的body請求建立對稱的格式數據, 例如.:

$ 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"
  },
  ...
}
複製代碼

提供資源的惟一標識

在默認狀況給每個資源一個id屬性. 用此做爲惟一標識除非你有更好的理由不用.不要使用那種在服務器上或是資源中不是全局惟一的標識,好比自動增加的id標識。

返回的惟一標識要用小寫字母並加個分割線格式 8-4-4-4-12, 例如.:

"id": "01234567-89ab-cdef-0123-456789abcdef"
複製代碼

提供標準的時間戳

提供默認的資源建立時間,更新時間 created_at and updated_at , 例如:

{
  ...
  "created_at": "2012-01-01T12:00:00Z",
  "updated_at": "2012-01-01T13:00:00Z",
  ...
}
複製代碼

這些時間戳可能不適用於某些資源,這種狀況下能夠忽略省去。

使用ISO8601的國際化時間格式

在接收的返回時間數據時只使用UTC格式. 查閱ISO8601時間格式, 例如:

"finished_at": "2012-01-01T12:00:00Z"
複製代碼

使用統一的資源路徑

資源命名

使用複數形式爲資源命名

形爲

好的末尾展示形式不準要指定特殊的資源形爲,在某些狀況下,指定特殊的資源的形爲是必須的,用一個標準的actions前綴去替代他, 清楚的描述他:

/resources/:resource/actions/:action
複製代碼

例如.

/runs/{run_id}/actions/stop
複製代碼

路徑和屬性要用小寫字母

使用小寫字母並用-短線分割路徑名字,而且緊跟着主機域名 e.g:

service-api.com/users
service-api.com/app-setups
複製代碼

一樣屬性也要用小寫字母, 可是屬性名字要用下劃線_分割。例如.:

"service_class": "first"
複製代碼

嵌套外鍵關係

序列化的外鍵關係一般創建在一個有嵌套關係的對象之上, 例如.:

{
  "name": "service-production",
  "owner": {
    "id": "5d8201b0..."
  },
  ...
}
複製代碼

而不是這樣 例如:

{
  "name": "service-production",
  "owner_id": "5d8201b0...",
  ...
}
複製代碼

這種方式儘量的把相關聯的資源信息內聯在一塊兒,而不用改變響應資源的結構,或者展現更高一級的響應區域, 例如:

{
  "name": "service-production",
  "owner": {
    "id": "5d8201b0...",
    "name": "Alice",
    "email": "alice@heroku.com"
  },
  ...
}
複製代碼

支持方便的無id間接引用

在某些狀況下,爲了方便用戶使用接口,在末尾提供用id標識資源,例如,一個用戶想到了他在heroku平臺app的名字,可是這個app的惟一標識是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
複製代碼

不要只接受使用名字而剔除了使用id。

構建錯誤信息

在網絡請求響應錯誤的時候,返回統一的,結構化的錯誤信息。要包含一個機器可讀的錯誤 id,一我的類能識別的錯誤信息 message, 根據狀況能夠添加一個url ,告訴客戶端關於這個錯誤的更多信息以及如何去解決它。 例如:

HTTP/1.1 429 Too Many Requests
複製代碼
{
  "id":      "rate_limit",
  "message": "Account reached its API rate limit.",
  "url":     "https://docs.service.com/rate-limits"
}
複製代碼

把你的錯誤信息格式文檔化,以及這些可能的錯誤信息ids 讓客戶端能獲取到.

用id來跟蹤每次的請求

在每個API響應中要包含一個Request-Id頭信息, 一般用惟一標識UUID. 若是服務器和客戶端都打印出他們的Request-Id, 這對咱們的網絡請求調試和跟蹤很是有幫助.

按範圍分頁

對於服務器響應的大量數據咱們應該爲此分頁。 使用Content-Range 頭傳遞分頁請求的數據.這裏有個例子詳細的說明了請求和響應頭、狀態碼,限制條件、排序以及分頁處理:Heroku Platform API on Ranges.

注:服務器會在響應頭中添加 Accept-Ranges: bytes 來表示支持 Range 的請求,以後客戶端纔可能發起帶 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
複製代碼

顯示速度限制狀態

客戶端的訪問速度限制能夠維護服務器的良好狀態,進而爲其餘客戶端請求提供高性的服務

爲每個帶有 RateLimit-Remaining 響應頭的請求,返回預留的請求tokens。

指定可接受頭信息的版本

在開始的時候指定API版本,使用Accepts頭傳遞版本信息,也能夠是一個自定義的內容, 例如:

Accept: application/vnd.heroku+json; version=3
複製代碼

最好不要給出一個默認的版本, 而是要求客戶端明確指明他們要使用特定的版本.

提供人類可讀的文檔

提供人類可讀的文檔讓客戶端開發人員能夠理解你的API。

除此之在詳細信息的結尾,提供一個關於以下信息的API摘要:

  • 驗證受權,包含獲取及使用驗證tokens.

  • API 穩定性及版本控制, 包含如何選擇所須要的版本.

  • 通常的請求和響應頭信息.

  • 錯誤信息序列格式.

  • 不一樣語言客戶端使用API的例子.

提供可執行的示例

提供可執行的示例讓用戶能夠直接在終端裏面看到API的調用狀況,最大程度的讓這些示例能夠逐字的使用,以減小用戶嘗試使用API的工做量。例如:

$ export TOKEN=... # acquire from dashboard
$ curl -is https://$TOKEN@service.com/users
複製代碼
相關文章
相關標籤/搜索