建立筋斗雲Web介面專案

天笑發表於2017-02-24

[任務]

用筋斗雲框架建立一個Web介面專案叫mysvc,建立資料庫,提供對ApiLog物件的操作介面。

先從github上下載開源的筋斗雲後端框架及示例應用:https://github.com/skyshore2001/jdcloud-php

建議安裝git工具直接下載,便於以後更新,例如直接建立Web介面專案叫mysvc:

git clone https://github.com/skyshore2001/jdcloud-php.git mysvc

如果github訪問困難,也可以用這個git倉庫: http://dacatec.com/git/jdcloud-php.git

配置好Web伺服器,php環境和MySQL資料庫。 注意PHP最低版本需要5.4版本,需要開啟mysql, pdo, gd等支援。

在Web伺服器上將專案下的介面主目錄(即server目錄)暴露出來,假設URL是:

http://localhost/mysvc/

先別急著訪問這個地址,而是先配置資料庫連線等,在瀏覽器中開啟這個頁面:

http://localhost/mysvc/tool/init.php

這個工具會先檢查執行環境是否正確,如有異常(比如php版本不對,缺少元件等)請先解決。 然後建立介面應用使用的資料庫和配置檔案。

初始化工具執行完後,生成的配置檔案為php/conf.user.php,之後也可以手工編輯該檔案。

資料模型定義在主設計文件DESIGN.wiki中,作為示例,裡面定義了一些資料模型,像使用者(User),訂單(Ordr)以及前面提過的操作日誌(ApiLog)等,還定義了一些常用介面,如登入操作(login)等。 我們通過通過命令列工具tool/upgrade.php可以建立或更新資料庫:

cd tool
php upgrade.php
(這時進入upgrade互動操作,輸入initdb命令建立或更新資料庫)
> initdb
(輸入命令q退出)
> q

我們進入server目錄看看:

  • api.php就是介面應用程式,提供Web介面。
  • tool目錄中是一些線上工具,比如檢視日誌、計劃任務等。
  • 物件型介面一般寫在檔案php/api_objects.php中,函式型介面一般寫在php/api_functions.php中。 裡面已經包含了一些示例介面,一般在示例基礎上修改即可。
  • 共用邏輯寫在app.php中,各種工具和介面應用程式均可用;注意如果只是多個介面共用的邏輯,直接寫在api.php檔案中就可以。

為了學習物件型介面,我們將php/api_objects.php清空,從頭開始來寫,以暴露ApiLog物件為例,在php/api_objects.php中加上一句:

class AC_ApiLog extends AccessControl
{
}

這一句程式碼就提供了對ApiLog物件的標準增刪改查(CRUD)介面如下:

查詢物件列表,支援分頁、查詢條件、統計等:
ApiLog.query() -> table(id, tm, addr)

新增物件,通過POST引數傳遞欄位值,返回新物件的id
ApiLog.add()(tm, addr) -> id

獲取物件
ApiLog.get(id) -> {id, tm, addr}

更新物件,通過POST引數傳遞欄位值。
ApiLog.set(id)(tm?, addr?)

刪除物件
ApiLog.del(id)

[介面原型的描述方式]

在上面的介面原型描述中,用了兩個括號的比如add/set操作,表示第一個括號中的引數通過GET引數(也叫URL引數)傳遞,第二個括號中的引數用POST引數(也叫FORM引數)傳遞。 多數介面引數支援用GET方式或POST方式傳遞,除非在介面說明中特別指定。 帶"?"表示引數或返回的屬性是可選項,可以不存在。

介面原型中只描述呼叫成功時返回資料的資料結構,完整的返回格式是[0, 返回資料];而在呼叫失敗時,統一返回[非0錯誤碼, 錯誤資訊]

我們可以直接用curl工具來模擬前端呼叫,用add介面新增一行資料,使用HTTP POST請求:

curl http://localhost/mysvc/api.php/ApiLog.add -d "tm=2016-9-9 10:10" -d "addr=shanghai"

curl用"-d"引數指定引數通過HTTP body來傳遞,由於預設使用HTTP POST謂詞和form格式(Content-Type=application/x-www-form-urlencoded), 這種引數一般稱為POST引數或FORM引數,與通過URL傳遞的GET引數相區別。 結果輸出一個JSON陣列:

[0,11338]

0表示呼叫成功,後面是成功時返回的資料,add操作返回物件id,可供get/set/del操作使用。

用get介面取出這個物件出來看看:

curl http://localhost/mysvc/api.php/ApiLog.get?id=11338

輸出:

[0,{"id":11338,"tm":"2016-09-09 00:00:00","addr":"shanghai"}]

這裡引數id是通過URL傳遞的。 前面說過,未顯式說明時,介面的引數可以通過URL或POST引數方式來傳遞,所以本例中URL引數id也可以通過POST引數來傳遞:

curl http://localhost/mysvc/api.php/ApiLog.get -d "id=11338"

如果取一個不存在的物件,會得到錯誤碼和錯誤資訊,比如:

curl http://localhost/mysvc/api.php/ApiLog.get?id=999999

輸出:

[1,"引數不正確"]

再用set介面做一個更新,按介面要求,要將id引數放在URL中,要更新的欄位及值用POST引數:

curl http://localhost/mysvc/api.php/ApiLog.set?id=11338 -d "addr=beijing"

輸出:

[0, "OK"]

再看很靈活的query介面,取下列表,預設支援分頁,會輸出一個nextkey欄位:

curl http://localhost/mysvc/api.php/ApiLog.query

返回示例:

[0,{
    "h":["id","tm","addr"],
    "d":[[11353,"2016-01-04 18:31:06","::1"],[11352,"2016-02-04 18:30:43","::1"],...],
    "nextkey":11349
}]

返回的格式稱為壓縮表,"h"為表頭欄位,"d"為表的資料,在介面描述中用table(id, 其它欄位...)表示。

預設返回的JSON資料未經美化,效率較高,如果想看的清楚些,可以在配置檔案conf.user.php中設定測試模式:

putenv("P_TEST_MODE=1");

測試模式不僅美化輸出資料,還可返回更多除錯資訊,前端可用URL引數_debug設定除錯等級0-9,如果設定為9,甚至可以檢視SQL呼叫日誌:

curl http://localhost/mysvc/api.php/ApiLog.query?_debug=9

這在除錯SQL語句時很有用。此外,測試模式還會開放某些內部介面,以及預設允許跨域訪問,便於通過web頁面測試介面。注意線上生產環境絕不可設定為測試模式。

query介面也支援常用的陣列返回,需要加上_fmt=list引數:

curl http://localhost/mysvc/api.php/ApiLog.query -d "_fmt=list"

返回示例:

[0,{
    "list": [
        { "id": 11353, "tm": "2016-01-04 18:31:06", "addr": "::1" },
        { "id": 11352, "tm": "2016-02-04 18:30:43", "addr": "::1" }, 
        ...
    ],
    "nextkey":11349
}]

還可以將_fmt引數指定為"csv", "excel", "txt"等,在瀏覽器訪問時可直接下載相應格式的檔案,讀者可自己嘗試。

取下一頁可以用_pagekey欄位,還可指定一次取的資料條數,用_pagesz欄位:

curl "http://localhost/mysvc/api.php/ApiLog.query?_pagekey=11349&_pagesz=5"

不僅支援分頁,query介面非常靈活,可以指定返回欄位、查詢條件、排序方式, 比如查詢2016年1月份的資料(cond引數),結果只需返回id, addr欄位(res引數,也可用於get介面),按id倒序排列(orderby引數):

curl http://localhost/mysvc/api.php/ApiLog.query -d "res=id,addr" -d "cond=tm>='2016-1-1' and tm<'2016-2-1'" -d "orderby=id desc"

甚至可以做統計,比如檢視2016年1月裡,列出訪問次數排名前10的地址,以及每個地址訪問了多少次伺服器,也可以通過query介面直接查出。 做一個按addr欄位的分組統計(gres引數):

curl http://localhost/mysvc/api.php/ApiLog.query -d "gres=addr" -d "res=count(*) cnt" -d "cond=tm>='2016-1-1' and tm<'2016-2-1'" -d "orderby=cnt desc" -d "_pagesz=10"

輸出示例:

[0,{
    "h":["addr","cnt"],
    "d":[["140.206.255.50",1],["101.44.63.119",73],["121.42.0.85",70],...],
    "nextkey": 3
}]

[介面呼叫的描述方式]

在之後的示例中,我們將使用介面原型來描述一個呼叫,不再使用curl,比如上面的呼叫將表示成:

ApiLog.query(gres=addr
    res="count(*) cnt"
    cond="tm>'2016-1-1' and tm<'2016-2-1'"
    orderby="cnt desc"
    _pagesz=10
)
->
{
    "h":["addr","cnt"],
    "d":[["140.206.255.50",1],["101.44.63.119",73],["121.42.0.85",70],...],
    "nextkey": 3
}

返回資料如非特別宣告,我們將只討論呼叫成功時返回的部分,比如說返回"OK"實際上表示返回[0, "OK"]

相關文章