goweb,基於go語言API框架

Alber發表於2018-01-17

goweb

一個基於 go 語言的快速開發 WebAPI 的工具,這個工具受到了 SpringMVC 的啟發,結合了 go 語言本身的特性,整體比較簡單,接下來,看看如何使用它。

下載安裝:

go get github.com/alberliu/goweb

1.核心功能

請求體引數注入

package main

import "github.com/alberliu/goweb"

type User struct {
    Id   int    `json:"id"`
    Name string `json:"name"`
}

func handler(user User) User {
    return user
}

func main() {
    goweb.HandlePost("/test", handler)
    goweb.ListenAndServe(":8000")
}

請求體:

{
    "id": 1,
    "name": "alber"
}

響應體:

{
    "id": 1,
    "name": "alber"
}

上面的程式碼是一個最簡的例子,HandlePost(string, interface{}) 會將一個 handler 註冊到一個全域性的內建的 goweb 例項 defultGoWeb,ListenAndServe(":8000") 會將 defultGoWeb 賦給 Server 的 handler 變數,然後啟動這個 Server。(是不是和內建的 ServerMux 有點像)

goweb 會自動解析註冊到它本身的 handler,當請求到來時,會將請求體的 json 資料反序列化並注入到 handler 的引數,handler 處理完邏輯返回時,會將 handler 的返回值序列化為 json 資料返回。goweb 預設使用 json 的序列化和反序列化方式,當然你可以定義自己的序列化方式,這個在後面你可以看到。

例子給出的 handler 的引數和返回都是結構體型別,當然你也可以使用指標型別。

結構體 goweb 其實本質上就是一個路由,它實現了 Handler 介面。上面的例子都是預設的 defultGoWeb,你也可以自己例項化一個 goweb。

func main() {
    goweb:=goweb.NewGoWeb();
    goweb.HandlePost("/test", handler)
    server := &http.Server{Addr: ":8000", Handler: goweb}
    server.ListenAndServe()
}

url 引數注入

package main

import "github.com/alberliu/goweb"

type User struct {
    Id   int64  `json:"id"`
    Name string `json:"name"`
}

func handler(id int64, name string) User {
    return User{id, name}
}

func main() {
    goweb := goweb.NewGoWeb();
    goweb.HandleGet("/test/{id}/{name}", handler)
    goweb.ListenAndServe(":8000")
}

執行上面的程式碼,然後訪問 url:http://localhost:8000/test/123456/alber

就可以返回下面的 json 資料

{
    "id": 123456,
    "name": "alber"
}

handler 可以獲取到 url 中的引數,並且注入到 handler 引數中。handler 的第一個引數對應 url 中的第一個引數,第二個引數對應 url 中的的第二個引數,依次類推。不過暫時還有個限制,在 url 中使用引數時,handler 中的引數必須與 url 中的引數個數一致,且型別必須為 string 或者 int64。

2.handler

goweb 可以註冊多種形式的 handler,goweb 會利用反射自動解析函式,支援多種型別,但是不能超出它可以解析的範圍。以下是它所有能解析的型別。


func handler(ctx goweb.Context) {
}

func handler(ctx goweb.Context) User {
    return User{}
}

func handler(user User) User {
    return User{}
}

func handler(ctx goweb.Context, user User) User {
    return User{}
}

func handler(name string, id int64) User {
    return User{}
}

func handler(ctx goweb.Context, name string, id int64) User {
    return User{}
}

Context 是一個請求上下文,他只有 ResponseWriter 和 Request 兩個欄位,它的內部結構如下所示。你可以根據自己的需求修改原始碼進行擴充套件,例如,把它作為一個請求的會話使用。

type Context struct {
    w http.ResponseWriter
    r *http.Request
}

3.用 Group 組織你的 handler

func main() {
    group1:=goweb.NewGroup("/group1")
    group1.HandleGet("/handler1",handler)
    group1.HandleGet("/handler2",handler)
    group1.HandleGet("/handler3",handler)

    group2:=goweb.NewGroup("/group2")
    group2.HandleGet("/handler1",handler)
    group2.HandleGet("/handler2",handler)
    group2.HandleGet("/handler3",handler)

    group3:=goweb.NewGroup("/group3")
    group3.HandleGet("/handler1",handler)
    group3.HandleGet("/handler2",handler)
    group3.HandleGet("/handler3",handler)

    goweb.HandleGroup(group1)
    goweb.HandleGroup(group2)
    goweb.HandleGroup(group3)
    goweb.ListenAndServe(":8000")
}

group 可以幫助你分層次的組織你的 handler,使你的路由結構更清晰。

4.定義自己序列化和反序列化方式

var json = jsoniter.ConfigCompatibleWithStandardLibrary

func jsonUnmarshal(data []byte, v interface{}) error {
    return json.Unmarshal(data, v)
}

func jsonMarshal(v interface{}) ([]byte, error){
    return json.Marshal(v)
}

func main() {
    goweb:=goweb.NewGoWeb();
    goweb.Unmarshal=jsonUnmarshal
    goweb.Marshal=jsonMarshal

    goweb.ListenAndServe(":8000")

}

goweb 預設採用 json(使用的是開源的 jsoniter) 序列化和反序列化資料,goweb 的 Marshal、Unmarshal 變數本身是一個函式.如果你想定義自己的序列化方式,只需要覆蓋掉它就行,就像上面那樣。

5.攔截器


func interceptor1(http.ResponseWriter, *http.Request) bool {
    return true
}
func interceptor2(http.ResponseWriter, *http.Request) bool {
    return true
}
func interceptor3(http.ResponseWriter, *http.Request) bool {
    return true
}

func main() {
    goweb := goweb.NewGoWeb();
    goweb.AddInterceptor(interceptor1)
    goweb.AddInterceptor(interceptor2)
    goweb.AddInterceptor(interceptor3)
    goweb.ListenAndServe(":8000")
}

goweb 在執行 handler 之前,會執行一個或者多個 interceptor,並且會根據 AddInterceptor 的先後順序執行,當 interceptor 返回 true 時,會接著往下執行,返回 false 時,會終止執行。

6.過濾器

func filter(w http.ResponseWriter, r *http.Request, f func(http.ResponseWriter, *http.Request)) {
    f(w, r)
}

func main() {
    goweb := goweb.NewGoWeb();
    goweb.Filter = filter
    goweb.ListenAndServe(":8000")
}

你可以給 goweb 新增一個過略器,在過濾器中,如果你想執行完自己的邏輯之後,執行 handler,只需要呼叫 f(w, r)。

7.自定義錯誤處理


func handler400(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(400)
    w.Write([]byte("bad request"))
}
func handler404(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(404)
    w.Write([]byte("url not found"))
}
func handler405(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(405)
    w.Write([]byte("method not found"))
}

func main() {
    goWeb := goweb.NewGoWeb()
    goWeb.Handler400 = handler400
    goWeb.Handler404 = handler404
    goWeb.Handler405 = handler405

    goweb.ListenAndServe(":8000")
}

當請求執行失敗時,goweb 中給出了一些預設的錯誤處理方式,就像上面那樣。當然,你也可以定義一些自己錯誤處理方式。

寫在後面

如果你有什麼好的建議,可以發我郵箱,一起交流。

alber_liu@qq.com

更多原創文章乾貨分享,請關注公眾號
  • goweb,基於go語言API框架
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章