首先要說明的是,這里實現(xiàn)的異步推送服務(wù)采用的是Long Polling方式,并不是Comet。
成都創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供淮安區(qū)網(wǎng)站建設(shè)、淮安區(qū)做網(wǎng)站、淮安區(qū)網(wǎng)站設(shè)計、淮安區(qū)網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、淮安區(qū)企業(yè)網(wǎng)站模板建站服務(wù),10多年淮安區(qū)做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
如果想用Comet來實現(xiàn)的話,可以參考這個開源項目:http://cometd.org/。不過其中的服務(wù)端實現(xiàn)只有Java版和Python版。如果要用Go來做后端的話需要自己實現(xiàn)Bayeux協(xié)議。
關(guān)于異步推送服務(wù)的解決方案的資料有很多,在這里就不在贅述了。當然,當前最先進的兩個方案就是Long Polling和Comet。
1. 預(yù)備知識
1.1 Go語言
關(guān)于Go語言,其實要說的很多。但是為了不跑題,請大家移步到這里:http://code.google.com/p/golang-china/。另外,Go語言的官網(wǎng)地址是:http://golang.org/。
1.2 Hijack
Hijack其實是一個單詞,雖然有很多人把它和電影《泰坦尼克號》中Rose的召喚聯(lián)系到一起。Hijack被譯為劫持,在“處理HTTP請求”的這個上下文中,就意味著可以讓我們“劫持”(或者說“保持”)HTTP請求鏈接,做一些其他操作(比如根據(jù)需要修改HTTP響應(yīng)的內(nèi)容),然后再在之后的某個時間將響應(yīng)“推送”回去。說到這,我想這就與Long Polling的運作方式很相似了。
Go語言的Hijack接口非常簡單,我們在官方的文檔站點上可以找到說明:http://godoc.org/net/http#Hijacker。本文中的核心代碼也是來自于此文檔。
1.3 jQuery
jQuery作為當今最流行的Javascript開發(fā)框架,我想基本上每一個做過Web開發(fā)的人都會知道,所以在這里我就不多說了。如果你不知道,可以看這里:http://jquery.com/。
2. 實戰(zhàn)
2.1 需求
在本案例中,我需要做一個能實時查看當前授權(quán)碼的頁面,而且我不想手動刷新頁面。另外,我還想記錄一下從頁面打開到當前時刻授權(quán)碼改變過多少次。因為授權(quán)碼在被使用后會自動變更一次,所以授權(quán)的變更次數(shù)就等于使用授權(quán)碼服務(wù)的人數(shù)。
2.2 編寫服務(wù)端代碼
之前說了,我們使用Go語言來編寫后端代碼。我們要使用Go語言的官方http庫。
其中,我們需要用http.HandleFunc來注冊針對某個url的請求處理器。如下:
- http.HandleFunc("/auth_code", getAuthCodeForAdmin) //向http服務(wù)器注冊一個對指定url進行處理的函數(shù)。
在函數(shù)getAuthCodeForAdmin的簽名中,有兩個參數(shù)——http.Request對象指針和http.ResponseWriter對象。http.Request對象指針用來獲取請求信息,http.ResponseWriter對象用來寫入響應(yīng)。
如果要使用Go的Hijack方式來處理HTTP請求,就需要先import其官方的http包:
- import ( "net/http" )
之后,我們在處理函數(shù)getAuthCodeForAdmin中先將http.ResponseWriter對象顯式轉(zhuǎn)換為http.Hijacker接口:
- hj, ok := w.(http.Hijacker)
返回值中賦給“ok”變量的值代表轉(zhuǎn)換是否成功,如果不成功就說明http.ResponseWriter對象未實現(xiàn)http.Hijacker接口。
如果轉(zhuǎn)換成功,我們就可以調(diào)用http.Hijacker接口的Hijack方法來獲取連接對象及其讀寫緩存對象了:
- conn, bufrw, err := hj.Hijack()
返回值中,“conn”代表連接對象,“bufrw”代表該連接的讀寫緩存對象。
如果返回值“err”等于nil就說明獲取成功,我就可以繼續(xù)下面的事情了。但首先需要在函數(shù)推出前關(guān)閉連接,不論函數(shù)是否執(zhí)行成功以及是否有錯誤發(fā)生:
- defer conn.Close()
使用defer關(guān)鍵字意味著,讓程序執(zhí)行流程退出該函數(shù)前先執(zhí)行緊隨其后的語句或函數(shù)。這樣就保證了資源的及時釋放。
接下來,我們先觀測新的授權(quán)碼的出現(xiàn),當其出現(xiàn)后我們就使用連接讀寫緩存對象bufrw返回給http客戶端。從觀測到返回給http客戶端的時間并不確定,也許時間會很長,這也從側(cè)面體現(xiàn)了Long Polling中的Long??聪旅娴拇a:
- nacChan := make(chan string)
- triggerFunc := func(newAuthCode string) {
- nacChan <- newAuthCode
- }
- triggerId := fmt.Sprintf("long-polling|%s|%s|%d", loginName, groupName, time.Now().UnixNano())
- request.AddNewAuthCodeTrigger(triggerId, triggerFunc)
- defer request.DelNewAuthCodeTrigger(triggerId)
這段代碼其中包含的東西很多,我們不需要全搞明白,只要知道這是為新授權(quán)碼產(chǎn)生時間注冊一個觸發(fā)器就行了。
當新授權(quán)碼被產(chǎn)生后,充當觸發(fā)器的函數(shù)triggerFunc會被調(diào)用。它會向名為nacChan的Channel中添加一個元素。注意,這個Channel是字符串類型的,并且是阻塞式。阻塞式意味著獲取元素的語句會一直阻塞,直到該Channel被添入元素。另外,當Channel中已有一個元素時,添加元素的語句也會被阻塞。我們在這里只用到了阻塞式Channel的前一個特性。元素獲取語句是這樣寫的:
- newAuthCode := <-nacChan
獲取到新授權(quán)碼后,程序會立即把它“push”給http客戶端。
- done := pushResponse(bufrw, newAuthCode)
函數(shù)pushResponse的完整定義如下:
- func pushResponse(bufrw *bufio.ReadWriter, authCode string) bool {
- _, err := bufrw.Write([]byte(authCode)) if err == nil {
- err = bufrw.Flush()
- } if err != nil {
- go_lib.LogErrorf("PushAuthCodeError: %s\n", err)
- return false
- }
- return true
- }
其中用到了很多“net/http”以外的包,關(guān)于它們的說明可以到Go文檔站點http://godoc.org/中查找。另外,“go_lib”是我為了自己開發(fā)方便而寫的一個函數(shù)庫,源碼在這里:https://github.com/hyper-carrot/go_lib,有興趣的讀者可以查看。
至此,基于Long Polling的異步推送服務(wù)的服務(wù)端就完成了。函數(shù)getAuthCodeForAdmin的完整代碼可以參看:https://github.com/hyper-carrot/hypermind/blob/master/server.go#L244。
2.2 編寫客戶端代碼
相應(yīng)的客戶端代碼相當簡單,如下:
- $(document).ready(function() {
- url = "/auth_code" count = 0 function poll_auth_code() {
- $.ajax({ url: url, success: function(data) { if (count == 0) {
- $("#initial").text(data);
- url += "?type=lp" }
- $("#current").text(data);
- $("#count").text(count);
- count++
- }, dataType: "text", complete: poll_auth_code, timeout: (1000 * 60 * 10) });
- }
- poll_auth_code()
- });
它整體采用了一種基于timeout的循環(huán)機制,邏輯相當簡單,我在這就不多說了,源碼在此:https://github.com/hyper-carrot/hypermind/blob/master/web/page/admin_auth_code.gtpl#L15。
部分頁面的快照如下圖:
3. 結(jié)束語
怎么樣?很簡單吧?基于這些代碼,我們還可以實現(xiàn)更復(fù)雜一些、更有趣的異步推送功能。
在這之后,我試著用Go Hijack和jQuery實現(xiàn)基于Comet的異步推送,但是由于未找到j(luò)Query中對HTTP請求響應(yīng)內(nèi)容細粒度的處理方法,暫時放棄了。Long Polling對于我這里的需求來講是夠用了。
另外再提一點。對比基于Long Polling方式Comet方式異步推送服務(wù),它們各有利弊。簡單來說,前者會更多的消耗請求處理資源,后者會更多的消耗服務(wù)器端口資源。個人感覺,在大量推送請求的場景下,還是Long Polling方式更好一些,因為它會比Comet方式更加及時的釋放資源。但是,基于Comet方式的異步推送服務(wù)在“push”速度上占有優(yōu)勢,也大大降低了漏掉推送消息的可能性。當然,我們可以通過在基于Long Polling方式的客戶端代碼中設(shè)置足夠長的timeout時間來模仿Comet方式。
最后,我認為實現(xiàn)Comet方式的最佳方式是WebSocket。所以讓我們摒棄掉低版本的網(wǎng)絡(luò)瀏覽器吧!
新聞名稱:使用GoHijack和jQuery輕松實現(xiàn)異步推送服務(wù)
文章鏈接:http://sd-ha.com/article14/ghdide.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄、、營銷型網(wǎng)站建設(shè)、網(wǎng)站導(dǎo)航、微信公眾號、定制開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)