讓我們以一個完整的Go程序示例 —— 一個web服務 —— 來作為這篇文檔的結尾。事實上,這個例子其實是一類“Web re-server”,也就是說它其實是對另一個Web服務的封裝。谷歌公司提供了一個用來自動將數據格式化為圖表或圖形的在線服務,其網址是:[http://chart.apis.google.com](http://chart.apis.google.com/)。 這個服務使用起來其實有點麻煩 —— 你需要把數據添加到URL中作為請求參數,因此不易于進行交互操作。我們現在的這個程序會為用戶提供一個更加友好的界面來處理某種形式的數據:對于給定的 一小段文本數據,該服務將調用圖標在線服務來產生一個QR碼,它用一系列二維方框來編碼文本信息。可以用手機攝像頭掃描該QR碼并進行交互操作,比如將 URL地址編碼成一個QR碼,你就省去了往手機里輸入這個URL地址的時間。
下面是完整的程序代碼,后面會給出詳細的解釋。
~~~
package main
import (
"flag"
"html/template"
"log"
"net/http"
)
var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
var templ = template.Must(template.New("qr").Parse(templateStr))
func main() {
flag.Parse()
http.Handle("/", http.HandlerFunc(QR))
err := http.ListenAndServe(*addr, nil)
if err != nil {
log.Fatal("ListenAndServe:", err)
}
}
func QR(w http.ResponseWriter, req *http.Request) {
templ.Execute(w, req.FormValue("s"))
}
const templateStr = `
<html>
<head>
<title>QR Link Generator</title>
</head>
<body>
{{if .}}
<img src="http://chart.apis.google.com/chart?chs=300x300&cht=qr&choe=UTF-8&chl={{.}}" />
<br>
{{.}}
<br>
<br>
{{end}}
<form action="/" name=f method="GET"><input maxLength=1024 size=70
name=s value="" title="Text to QR Encode"><input type=submit
value="Show QR" name=qr>
</form>
</body>
</html>
`
~~~
`main`函數之前的部分很容易理解。包flag用來構建我們這個服務默認的HTTP端口。從模板變量`templ`開始進入了比較好玩的部分,它的功能是用來構建一個HTML模板,該模板被我們的服務器處理并用來顯式頁面信息;我們后面還會看到更多細節。
`main`函數使用我們之前介紹的機制來解析flag,并將函數`QR`綁定到我們服務的根路徑。然后調用`http.ListenAndServe`方法啟動服務;該方法將在服務器運行過程中一直處于阻塞狀態。
`QR`函數用來接收包含格式化數據的請求信息,并以該數據`s`為參數對模板進行實例化操作。
模板包`html/template`的功能非常強大;上述程序僅僅觸及其冰山一角。本質上說,它會根據傳入`templ.Execute`方法的參數,在本例中是格式化數據,在后臺替換相應的元素并重新生成HTML文本。在模板文本(`templateStr`)中,雙大括號包裹的區域意味著需要進行模板替換動作。在`{{if .}}`和`{{end}}`之間的部分只有在當前數據項,也就是`.`,不為空時才被執行。也就是說,如果對應字符串為空,內部的模板信息將被忽略。
代碼片段`{{.}}`表示在頁面中顯示傳入模板的數據 —— 也就是查詢字符串本身。HTML模板包會自動提供合適的處理方式,使得文本可以安全的顯示。
模板串的剩余部分就是將被加載顯示的普通HTML文本。如果你覺得這個解釋太籠統了,可以進一步參考[Go文檔](http://localhost:6060/pkg/html/template/)中,關于模板包的深入討論。
看,僅僅用了很少量的代碼加上一些數據驅動的HTML文本,你就搞定了一個很有用的web服務。這就是Go語言的牛X之處:用很少的一點代碼就能實現很強大的功能。