# API的設計
OpenResty,最擅長的應用場景之一就是API Server。如果我們只有簡單的幾個API出口、入口,那么我們可以相對隨意簡單一些。
> 舉例幾個簡單API接口輸出:
~~~
server {
listen 80;
server_name localhost;
location /app/set {
content_by_lua "ngx.say('set data')";
}
location /app/get {
content_by_lua "ngx.say('get data')";
}
location /app/del {
content_by_lua "ngx.say('del data')";
}
}
~~~
當你的API Server接口服務比較多,那么上面的方法顯然不適合我們(太啰嗦)。這里推薦一下REST風格。
#### 什么是REST
從資源的角度來觀察整個網絡,分布在各處的資源由URI確定,而客戶端的應用通過URI來獲取資源的表示方式。獲得這些表徵致使這些應用程序轉變了其狀態。隨著不斷獲取資源的表示方式,客戶端應用不斷地在轉變著其狀態,所謂表述性狀態轉移(Representational State Transfer)。
這一觀點不是憑空臆造的,而是通過觀察當前Web互聯網的運作方式而抽象出來的。Roy Fielding 認為,
~~~
設計良好的網絡應用表現為一系列的網頁,這些網頁可以看作的虛擬的狀態機,用戶選擇這些鏈接
導致下一網頁傳輸到用戶端展現給使用的人,而這正代表了狀態的轉變。
~~~
> REST是設計風格而不是標準。
REST通常基于使用HTTP,URI,和XML以及HTML這些現有的廣泛流行的協議和標準。
- 資源是由URI來指定。
- 對資源的操作包括獲取、創建、修改和刪除資源,這些操作正好對應HTTP協議提供的GET、POST、PUT和DELETE方法。
- 通過操作資源的表現形式來操作資源。
- 資源的表現形式則是XML或者HTML,取決于讀者是機器還是人,是消費web服務的客戶軟件還是web瀏覽器。當然也可以是任何其他的格式。
> REST的要求
- 客戶端和服務器結構
- 連接協議具有無狀態性
- 能夠利用Cache機制增進性能
- 層次化的系統
#### REST使用舉例
按照REST的風格引導,我們有關數據的API Server就可以變成這樣。
~~~
server {
listen 80;
server_name localhost;
location /app/task01 {
content_by_lua "ngx.say(ngx.req.get_method() .. ' task01')";
}
location /app/task02 {
content_by_lua "ngx.say(ngx.req.get_method() .. ' task02')";
}
location /app/task03 {
content_by_lua "ngx.say(ngx.req.get_method() .. ' task03')";
}
}
~~~
對于`/app/task01`接口,這時候我們可以用下面的方法,完成對應的方法調用。
~~~
# curl -X GET http://127.0.0.1/app/task01
# curl -X PUT http://127.0.0.1/app/task01
# curl -X DELETE http://127.0.0.1/app/task01
~~~
#### 還有辦法壓縮不?
上一個章節,如果task類型非常多,那么后面這個配置依然會隨著業務調整而調整。其實每個程序員都有一定的潔癖,是否可以以后直接寫業務,而不用每次都修改主配置,萬一改錯了,服務就起不來了。
引用一下HttpLuaModule官方示例代碼。
~~~
# use nginx var in code path
# WARNING: contents in nginx var must be carefully filtered,
# otherwise there'll be great security risk!
location ~ ^/app/([-_a-zA-Z0-9/]+) {
set $path $1;
content_by_lua_file /path/to/lua/app/root/$path.lua;
}
~~~
這下世界寧靜了,每天寫Lua代碼的同學,再也不用去每次修改Nginx主配置了。有新業務,直接開工。順路還強制了入口文件命名規則。對于后期檢查維護更容易。
#### REST風格的缺點
需要一定的學習成本,如果你的接口是暴露給運維、售后、測試等不同團隊,那么他們經常不去確定當時的`method`。當他們查看、模擬的時候,具有一定學習難度。
REST 推崇使用 HTTP 返回碼來區分返回結果, 但最大的問題在于 HTTP 的錯誤返回碼 (4xx 系列為主) 不夠多,而且訂得很隨意。比如用 API 創建一個用戶,那么錯誤可能有:
- 調用格式錯誤(一般返回 400,405)
- 授權錯誤(一般返回 403)
- "運行期"錯誤
- 用戶名沖突
- 用戶名不合法
- email 沖突
- email 不合法
- 序
- Lua簡介
- Lua環境搭建
- 基礎數據類型
- 表達式
- 控制結構
- if/else
- while
- repeat
- 控制結構for的使用
- break,return
- Lua函數
- 函數的定義
- 函數的參數
- 函數的返回值
- 函數回調
- 模塊
- String庫
- Table庫
- 日期時間函數
- 數學庫函數
- 文件操作
- 元表
- 面向對象編程
- FFI
- LuaRestyRedisLibrary
- select+set_keepalive組合操作引起的數據讀寫錯誤
- redis接口的二次封裝(簡化建連、拆連等細節)
- redis接口的二次封裝(發布訂閱)
- pipeline壓縮請求數量
- script壓縮復雜請求
- LuaCjsonLibrary
- json解析的異常捕獲
- 稀疏數組
- 空table編碼為array還是object
- 跨平臺的庫選擇
- PostgresNginxModule
- 調用方式簡介
- 不支持事務
- 超時
- 健康監測
- SQL注入
- LuaNginxModule
- 執行階段概念
- 正確的記錄日志
- 熱裝載代碼
- 阻塞操作
- 緩存
- sleep
- 定時任務
- 禁止某些終端訪問
- 請求返回后繼續執行
- 調試
- 調用其他C函數動態庫
- 我的lua代碼需要調優么
- 變量的共享范圍
- 動態限速
- shared.dict 非隊列性質
- 如何添加自己的lua api
- 正確使用長鏈接
- 如何引用第三方resty庫
- 使用動態DNS來完成HTTP請求
- 緩存失效風暴
- Lua
- 下標從1開始
- 局部變量
- 判斷數組大小
- 非空判斷
- 正則表達式
- 不用標準庫
- 虛變量
- 函數在調用代碼前定義
- 抵制使用module()函數來定義Lua模塊
- 點號與冒號操作符的區別
- 測試
- 單元測試
- API測試
- 性能測試
- 持續集成
- 灰度發布
- web服務
- API的設計
- 數據合法性檢測
- 協議無痛升級
- 代碼規范
- 連接池
- c10k編程
- TIME_WAIT問題
- 與Docker使用的網絡瓶頸
- 火焰圖
- 什么時候使用
- 顯示的是什么
- 如何安裝火焰圖生成工具
- 如何定位問題