動態

詳情 返回 返回

搶佔式調度協程API服務器 - 動態 詳情

這篇文章的標題有些拗口,筆者簡單解釋一下。

本文是一款介紹開源API服務器Medge的文章。Medge是一個HTTP服務器,而其作者目前將其定位為API服務器方向。

在Medge中,我們可以通過腳本語言Melang來編寫和實現API邏輯。Melang是一種搶佔式調度的協程語言,其每一個腳本任務都被視為一個協程運行在同一個單一線程內部,依據執行步長輪詢調度。因此,在上層邏輯開發過程中,開發者無需考慮協程調度問題,也就無需考慮何時該調用某些特定函數讓出CPU執行權。

下面我們進入正題,看一個完整的簡單使用示例。

使用示例

當我們安裝好Medge後,我們可以在命令行中輸入

$ medge

來啓動HTTP服務器。

我們使用如下命令參數來啓動Medge:

$ medge -p 8080 -d /opt/medge/ -w 1

這裏,

  • -p 是用於指定該HTTP服務器監聽的TCP端口號,若不設置默認為80。本例中HTTP監聽0.0.0.0:8080
  • -d 是用於指定API服務的統一入口目錄路徑,本例中是/opt/medge。我們稍後會對這個目錄下的結構進行説明。若不指定本參數項,則默認為/opt/medge
  • -w 是用於指定HTTP的工作進程數。若不指定默認為1

此時,服務器已經啓動了,但是我們還沒有給出API服務的具體處理邏輯。那麼下面我們就來增加API服務。

上面提到了Medge的-d參數指定了API服務的統一入口目錄,下面我們就給出這一路徑下的大致目錄樹結構:

|- /opt/medge/
    |- service_1/
        |- entry.m
        |- ...
    |- service_2/
        |- entry.m
        |- ...

可以看到,在/opt/medge目錄下,存在兩個服務,即:service_1service_2,且每個服務下都有一個同名腳本文件entry.mentry.m是服務的入口文件,即當Medge收到HTTP請求,找到對應服務後,就會立刻執行該服務的entry.m腳本進行處理。

在我們的這個示例中,我們僅演示一個API服務,因此本例中的目錄樹結構為:

|- /opt/medge/
    |- 127.0.0.1:8080/
        |- entry.m
        |- index.m

這裏,127.0.0.1:8080是一個目錄,之所以起這樣的名字,是因為Medge中的服務名是以HTTP請求的Host命名和區分的。因為本例不存在使用域名發起HTTP請求,所以這裏的目錄名稱就是這樣一個IP+端口的形式。

下面,我們給出entry.mindex.m的腳本內容:

//entry.m
/*
 * Implement a simple controller.
 * There are three variable injected in this script task:
 *   1. Req. Its prototype is:
 *       Req {
 *           method; //string  e.g. GET POST DELETE ...
 *           version; //string e.g. HTTP/1.0 HTTP/1.1
 *           uri; //string e.g. /index/index
 *           args; //an key-value array, e.g. ["key":"val", ...]
 *           headers; //an key-value array, e.g. ["Content-Type":"application/json", ...]
 *           body; //string
 *       }
 *
 *    2. Resp. Its prototype is:
 *        Resp {
 *            version; //same as Req's version
 *            code; //integer  e.g. 200
 *            headers; //same as Req's headers
 *            body; //same as Req's body
 *        }
 *
 *.   3. Basedir. A string of the base directory path. (Not used in this example)
 */

#include "@/index.m"

str = Import('str');
sys = Import('sys');

uri = str.slice(Req.uri, '/');
ctlr = str.capitalize(uri[0]);
o = $ctlr;
if (sys.has(o, uri[1]) != 'method') {
  Resp.code = 404;
} else {
  o.__action__ = uri[1];
  Resp.body = o.__action__();
  Resp.headers['Content-Length'] = str.strlen(Resp.body);
}
//index.m

Json = Import('json');

Index {
    @index() {
        Resp.headers['Content-Type'] = 'application/json';
        return Json.encode(['code': 200, 'msg': 'OK']);
    }
}

可以看到,entry.m前面包含了一些註釋信息,其中提到,每個請求都會向其對應服務的entry.m腳本中注入3個變量:

  • Req 包含了請求有關的信息,如:方法、版本、資源路徑、參數、請求頭和請求體。
  • Resp 包含了響應有關的信息,如:版本(默認與請求版本一致)、響應狀態碼(默認為200)、響應頭和響應體。
  • Basedir 是一個字符串,內容為Medge -d參數指定的路徑。

簡單來説,本例中的entry.m實現了一個非常簡單的MVC框架中的控制器,它根據資源路徑找到對應的處理類和類方法,並調用它們來處理HTTP請求。

本例中,我們將使用如下命令發起HTTP請求:

$ curl -v http://127.0.0.1:8080/index/index

所以,entry中會先對資源路徑/index/index進行切片,獲取第一個index後將其首字母大寫。隨後使用這個修改後的字符串作為類名,查找當前腳本環境中是否存在一個名為Index的類。找到後,調用其index(即資源路徑的第二個index)方法處理請求。

在執行curl命令後,我們將看到其輸出大致為:

*   Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /index/index HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Length: 23
< Content-Type: application/json
< 
* Connection #0 to host 127.0.0.1 left intact
{"code":200,"msg":"OK"}

結束語

目前Medge還只是個實驗性項目,其中還有很多功能有待實現,例如目前它只支持HTTP/1.0 HTTP/1.1的版本,且暫未支持https。除此之外,目前Melang腳本僅支持MySQL數據庫,且還沒有對應的http庫函數或類供開發者使用。

感興趣的小夥伴可以訪問其Github倉庫。

感謝閲讀!

Add a new 評論

Some HTML is okay.