使用Go語言框架進行web開發筆記
前言
關於golang的web開發有不少框架,例如 martini, gin, revel,gorilla等。 之前玩過revel
,感覺封裝的太多了,作為一個小應用不需要這麼複雜,而且google得到結果是revel的效率相對較差。gin
的benchmark顯示效率是martini的40倍,但是gin比較新所以他的的生態圈相對較少。最終選擇了martini
, 有很多middleware可以選擇,其中就包括了websocket,並且背後用的是gorilla websocket這個包。
介面和功能
- 一個跳轉到Oauth2登陸授權頁面的連結
- 授權完成後,跳回服務的頁面,此時獲得了access_token, 就可以為所欲為了。全部的功能也都集中在這個頁面,最終的介面如下圖所示。
點選連線
是用來開啟websocket連線的。開始傳送資料
是開始把使用者ID發給服務端,服務端呼叫api開始抓取圖片。停止
用於停止本次的抓取服務。已完成數量
用於實時返回抓取的圖片數量。
程式大致結構
這裡把Jobs
, goroutine #1
, #2
等作用在全域性是為了在websocket斷開後,下載還能繼續執行。websocket goroutine
是連線建立後的作用域,連線斷開後這個goroutine就不存在了。Jobs
, NextUrl
充當佇列的角色。 Done
的作用僅僅是計數。這裡少寫了兩個全域性變數,Quit chan int
, IsPreparing bool
, 這兩個變數是用來讓前端控制抓取程式是否進行的。
簡單理解就是一個產生任務的for迴圈,一個消費任務的for迴圈,一個用於給client返回計數的for迴圈。這裡不得不感嘆,goroutine channel的設計使得編碼簡單明瞭。
遇到的問題
由於第一次正經使用Go,還是遇到不少問題的。不過需求比較簡單,所以沒有接觸什麼深入的內容。主要集中在強型別帶來的問題。
DB查詢
之前寫過一篇關於database/sql的文章,這次直接用了sqlx
這個庫,可以少寫不少程式碼,也少犯錯誤。但是畢竟不如laravel那麼方便,所幸需要寫的sql不多,臨時寫幾個方法就搞定。同時思考,如何實現一個eloquent的api。貌似有難度。
Json處理
強型別決定了Json的處理是個痛。之前寫過一個天氣預報的小程式,用的是map[string]*json.RawMessage
RawMessage
, 字串的引號"
也會被保留,使得字串結果前後多了引號。
這次再次google了一次,發現還是得用map[string]interface{}
來對映,然後再用type assertion
來一層層的解開json。這是一個痛苦的過程,想起php中的json_decode()
不禁淚流滿面。
Stop Goroutine
如何中斷一個goroutine是一個問題,因為需要控制開始停止。谷歌一下很快就有結果。
go func() { for { select { case <-Quit:
IsPreparingJobs = false
return
default: // to do something
}
}
}()
這裡設定一個IsPreparingJobs
是用於中斷後再次開始這個迴圈。
Testing
Golang提供的測試工具非常方便,go test
就能進行所有測試。從martini原始碼中複製了兩個常用方法出來。
func expect(t *testing.T, a interface{}, b interface{}) { if a != b {
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
func refute(t *testing.T, a interface{}, b interface{}) { if a == b {
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
總結
感覺golang作為web開發工具,在資料格式處理方面,沒有弱型別語言方便。這點node倒是非常好,json轉object非常方便。也許配合Promise,node會比較好用吧。golang也有優勢,goroutine非常好用,官方的庫功能非常全,打包為二進位制可執行檔案使得部署異常容易,強型別語言效率比較高。