這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
最近需要用Instagram的api抓取其使用者的圖片,由於需要用oauth2驗證, 所以應用必須包含一個web介面。設想能夠即時返回下載數量,所以用websocket。還有需要考慮到效率問題,綜合以上幾點,想用一門語言開發的話,最終選擇用golang進行開發,node的回調實在不喜歡。
前言
關於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
這種映射結構,然後一層一層解開json。當時沒發現這是有問題的,因為如果用RawMessage
, 字串的引號"
也會被保留,使得字串結果前後多了引號。
這次再次google了一次,發現還是得用map[string]interface{}
來映射,然後再用type assertion
來一層層的解開json。這是一個痛苦的過程,想起php中的json_decode()
不禁淚流滿面。
Stop Goroutine
如何中斷一個goroutine是一個問題,因為需要控制開始停止。Google一下很快就有結果。
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非常好用,官方的庫功能非常全,打包為二進位可執行檔使得部署異常容易,強型別語言效率比較高。
最後有感於前幾天的shadowsockets事件,作為一個ss使用者,除了感謝無私的開發人員,剩下的就只是憤怒和失望。昨天又看了老羅的T1發布會,Born to be proud
, 天生驕傲
,在堅持做人原則方面,老羅一直是我的楷模。期待今晚的鎚子發布會。