Go語言構(gòu)建 RESTful Web 服務(wù)
本文是 Hardcore Google 系列的一部分,本系列的其它部分于下面地址可以找到:
Go 語言實(shí)現(xiàn) REST 風(fēng)格網(wǎng)絡(luò)服務(wù)器
在開始著手開發(fā)網(wǎng)絡(luò)應(yīng)用之前,你需要先選擇你所用的工具集,以及它們之間的相互作用,這一步很重要。在我的項(xiàng)目中,我選擇 Go 語言作為后臺(tái),AngularJS 作為前臺(tái),而 Google App Engine 則為主機(jī)。于是,剩下的問題就是,Go 語言如何同 AngularJS 交互。幸運(yùn)的是,這真的太簡單了。
我選擇以 REST風(fēng)格的 API 進(jìn)行交互,因?yàn)檫@樣交互的方法組織良好,且網(wǎng)絡(luò)應(yīng)用的前端后端對(duì)其都支持良好。在我的開發(fā)生涯中,我發(fā)現(xiàn),我為了將兩種格格不如的東西統(tǒng)合到一起浪費(fèi)了太多頭腦,頭發(fā)都掉了不少,REST 很好。
使用 REST 風(fēng)格的網(wǎng)絡(luò)服務(wù)器意味著你將基于 HTTP 方法(例如 GET、POST、DELETE等)和URL網(wǎng)址管理你的數(shù)據(jù)。在 Go 語言的一端,你可以使用 net/http 包來處理 AngularJS 提交的請(qǐng)求。而在更高一級(jí),你可以這樣告訴 Go 語言如何處理請(qǐng)求:
- http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
- fmt.Fprintf(w, "Thanks for the %s!", r.Method)
- })
上面我們注冊(cè)了一個(gè)處理所有請(qǐng)求 /bar 的函數(shù)。每個(gè)對(duì)請(qǐng)求的處理函數(shù)都有相同的函數(shù)定義: 它以參數(shù)的形式,獲得輸出響應(yīng)的 http.ResponseWriter 和包含請(qǐng)求細(xì)節(jié)的 http.Request。這樣,當(dāng)我們啟動(dòng)這個(gè)服務(wù),并發(fā)起一個(gè) “DELETE /bar” 請(qǐng)求時(shí),我們將獲得 “Thanks for the DELETE!” 的返回。
我希望,你可以看看下一步的處理。在 Go 語言中實(shí)現(xiàn) REST 風(fēng)格的 API,你需要為每個(gè) URL 網(wǎng)址節(jié)點(diǎn)注冊(cè)處理函數(shù),并根據(jù)給出的方法實(shí)現(xiàn)處理程序。通過使用 gorilla/mux 包,這個(gè)過程將更簡單。它比 Go 語言默認(rèn)的 HTTP 處理器更底層,但它能夠更好的通過 HTTP 方法處理路由細(xì)節(jié)。下面就是例子:
- m := mux.NewRouter()
- // Get all lists.
- m.HandleFunc("/", GetAllLists).Methods("GET")
- // Make a new list.
- m.HandleFunc("/", PostList).Methods("POST")
- // Singe list operations.
- m.HandleFunc("/{key}/", GetList).Methods("GET")
- m.HandleFunc("/{key}/", PutList).Methods("PUT")
- m.HandleFunc("/{key}/", DeleteList).Methods("DELETE")
- // Everything else fails.
- m.HandleFunc("/{path:.*}", gorca.NotFoundFunc)
如你所見,我為每個(gè)需要的 REST 方法都注冊(cè)了處理程序。在這個(gè)例子里,我為網(wǎng)絡(luò)應(yīng)用的列表部分注冊(cè)了一些函數(shù)。我可以通過 GET 或是 POST 在根路徑( /)獲取和提交列表。如果我在 URL 中設(shè)定了一個(gè)鍵(/{key}/),我可以處理一個(gè)指定的列表。這樣,我可以通過GET, PUT和DELETE。獲取列表,上傳列表,或是刪除列表。
***的 HandleFunc 則用來處理其它未設(shè)定的請(qǐng)求。如果客戶端的請(qǐng)求并未明確列出,我們將返回一個(gè)404狀態(tài)和 JSON 格式的細(xì)節(jié)信息。net/http 包可以返回了一個(gè)簡單的404狀態(tài),但我希望同時(shí)能返回 JSON響應(yīng)。 使用全部抓取將允許我返回 JSON響應(yīng)。客戶端則可以為用戶顯示一個(gè)有效的信息,提示錯(cuò)誤所在,而不僅僅是一個(gè)簡單的“請(qǐng)求失敗”。
作為處理器(handler)的例子, GetAllLists 處理器代碼如下:
- // GetAllLists fetches all of the lists.
- func GetAllLists(w http.ResponseWriter, r *http.Request) {
- // Create the query.
- c := appengine.NewContext(r)
- q := datastore.NewQuery("List").Order("-LastModified")
- // Fetch the lists.
- lists := []List{}
- if _, err := q.GetAll(c, &lists); err != nil {
- gorca.LogAndUnexpected(c, w, r, err)
- return
- }
- // Write the lists as JSON.
- gorca.WriteJSON(c, w, r, lists)
- }
如果你對(duì) App Engine 不是很熟悉,代碼中的一些細(xì)節(jié)或許對(duì)你有些模糊,但我基本上獲取了 App Engine datastore 中的所有的列表數(shù)據(jù),并將其轉(zhuǎn)換為 JSON,作為響應(yīng)返回。
GetAllLists 函數(shù)顯示了 Go 如何同 App Engine 相結(jié)合,使開發(fā)變得簡單。短短的十幾行代碼,我可以創(chuàng)造一個(gè)強(qiáng)大的 REST 網(wǎng)絡(luò)服務(wù)器。我不必處理 MySQL 的連接、用戶認(rèn)證、或解析傳入的 HTTP 請(qǐng)求。 App Engine 和 Go 已經(jīng)為我做了處理。最終的結(jié)果就是,我擁有了更具可讀性、可測試性和可維護(hù)性的代碼。
你可以在我的代碼中看到我是如何為此而著迷的:
列表處理器函數(shù)(The List Handler Functions)
我真的驚訝于如此簡易的過程。安裝后臺(tái)環(huán)境很可能成為一個(gè)夢(mèng)魘。在工作中,我曾處理過一個(gè) SOAP 網(wǎng)絡(luò)服務(wù),我愿出庭作證:這個(gè)'S'(簡易的)是一個(gè)謊言。而對(duì) Go,這根本不是什么事兒。它已經(jīng)提供了強(qiáng)大的功能,且開源則意味著,只要你需要,大批如同 gorilla/mux 的包有的是。下一次,我將說說如何利用 Angular JS 處理我們發(fā)回的JSON。敬請(qǐng)期待。
原文鏈接:http://www.oschina.net/translate/hardcore-google-communicating-go