polaris: 一個用go實現的支持restful的web框架

介紹

polaris是一個用go實現的支持restful的web框架,主要參考tornado進行設計。

雖然在go裏面搭建一個http server非常的簡單,這裏強烈推薦gorilla,但並沒有很好的對restful模型進行支持。考察了很多開源實現,我決定還是重新造一個輪子,畢竟難度也不怎麼大,而且能夠根據項目的使用慢慢調整完善。

使用

設計polaris還是參考了tornado,雖然一段時間不用python了,但是我還是對tornado念念不忘。

polaris,我現在只支持get,post,put,head和delete這幾種method,剩下的貌似我也沒用到過。只要一個對象,它提供了以上一個或多個接口,就能註冊進polaris的router中。

先上一個例子:

type Handler1 struct {

}

func (h *Handler1) Prepare(env *Env) {
    fmt.Println("hello prepare")
}

func (h *Handler1) Get(env *Env) {
    env.WriteString("hello get")
}

func (h *Handler1) Post(env *Env) {
    env.WriteString("hello post")
}

type Handler2 struct {

}

//id is a captured submatch for regexp url below
func (h *Handler2) Get(env *Env, id string) {
    env.WriteString("hello " + id)
}

r = NewRouter()

r.Handle("/handler1", new(Handler1))
r.Handle("/handler2/([0-9]+)", new(Handler2))

http.Handle("/", r)
http.ListenAndServe("127.0.0.1:11181", nil)

上面,我們實現了兩個handler,對於每一個handler,需要實現以下一個或多個接口:

Get(env *Env)
Post(env *Env)
Head(env *Env)
Put(env *Env)
Delete(env *Env)

Env用以表明該次請求的上下文環境,主要是爲了紀念一個內部庫stars,以此命名。

鑑於tornado也提供了prepare支持,所以,如果handler提供了Prepare(env *Env)接口,每次調用相應的函數的時候,會優先調用Prepare。

在handler2中,我們可以看到,Get函數多了一個參數id,這主要是爲了處理對應的正則url裏面含有group的情況。上面handler2對應的url裏面有一個([0-9]+) group,所以當url匹配成功之後,我們會將該group實際的數據傳遞給handler2。

因爲正則匹配的結果都是string,所以Get後面的參數都必須是string類型的。實際的類型轉換需要handler自行處理。

路由規則

polaris的路由規則比較簡單,參考nginx分爲literal pattern和regexp pattern兩種。當有請求需要處理的時候,首先查看是否在literal pattern中,如果不是,則根據註冊的regexp pattern依次匹配。

上面的例子中,/handler1就是literal pattern,而/handler2/([0-9]+)則是regexp pattern。在go中,判斷一個字符串是否是正則表達式,只要通過regexp.QuoteMeta就可以了,如果得到的值跟原字符串一樣,該字符串就是literal pattern。

實現

polaris核心實現是基於reflect,這裏列舉一些:

判斷一個handler是否具有相關接口

  • reflect.ValueOf(handler)得到handler的value v
  • v.MethodByName("Get")得到get function的value m
  • m.Kind() == reflect.Func判斷是否存在Get函數

判斷接口是否滿足規範

  • m.NumIn()獲取該函數輸入參數的個數
  • m.In(0).Kind() == reflect.Ptr和m.In(0).String() == "*polaris.Env"判斷第一個參數必須爲*Env
  • m.In(i).Kind() == reflect.String判斷第i(i>=1)個參數必須爲string

根據傳入的參數調用相應的函數

  • 根據傳入的http request method找到對應的函數 m
  • values = make([]relfect.Value, nArgs)
  • 通過reflect.ValueOf填充參數,第一個參數爲*Env
  • m.Call(values),使用Call進行函數調用

後續

現在的polaris只支持基本的restful模型,後續我考慮將自己開發的其他庫,譬如log,mysql等進行整合,使其真正成爲一個可用的restful web framework。

代碼在這裏https://github.com/siddontang/polaris,歡迎大家反饋。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章