## 5.15\. Web服務器
現在讓我們來實現一個完整的程序:一個簡單的web服務器。這其實是一個轉發服務器。 google的[http://chart.apis.google.com](http://chart.apis.google.com/) 提供了一個將數據轉換為圖表的服務。不過那個圖表的轉換程序使用比較復雜,因為需要用戶 自己設置各種參數。不過我們這里的程序界面要稍微友好一點:因為我們只需要獲取一小段數據, 然后調用google的圖表轉換程序生存QR碼(Quick Response縮寫,二維條碼),對于文本 信息下編碼。二維條碼圖像可以用手機上的攝像機采集,然后解析得到解碼后的信息。
下面是完整的程序:
```
package main
import (
"flag"
"http"
"io"
"log"
"strings"
"template"
)
var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
var fmap = template.FormatterMap{
"html": template.HTMLFormatter,
"url+html": UrlHtmlFormatter,
}
var templ = template.MustParse(templateStr, fmap)
func main() {
flag.Parse()
http.Handle("/", http.HandlerFunc(QR))
err := http.ListenAndServe(*addr, nil)
if err != nil {
log.Exit("ListenAndServe:", err)
}
}
func QR(c *http.Conn, req *http.Request) {
templ.Execute(req.FormValue("s"), c)
}
func UrlHtmlFormatter(w io.Writer, v interface{}, fmt string) {
template.HTMLEscape(w, strings.Bytes(http.URLEscape(v.(string))))
}
const templateStr = `
<html>
<head>
<title>QR Link Generator</title>
</head>
<body>
{.section @}
<img src="http://chart.apis.google.com/chart?chs=300x300&cht=qr&choe=UTF-8&chl={@|url+html}"
/>
<br>
{@|html}
<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=&##34;Show QR" name=qr>
</form>
</body>
</html>
`
```
main函數的開始部分比較簡單。有一個flag選項用于指定HTTP服務器的監聽端口。 還有一個模板變量templ,主要用于保存HTML頁面的生成模板,我們稍后會討論。
main首先分析命令行選項,然后幫定QR函數為服務器的根目錄 處理函數。最后http.ListenAndServe啟動服務器,并在服務器運行期間一直 阻塞。
QR接收客戶端請求,然后用表單中的s變量的值替換到模板。
template包實現了json-template。 我們的程序的簡潔正是得益于template包的強大功能。本質上,在執行templ.Execute的 時候,根據需要替換調模板中的某些區域。這里的原始模板文本保存在templateStr中, 其中花括弧部分對應模板的動作。在{.section @}和{.end}之間的 以@開頭的元素,在處理模板的時候會被替換。
標記{@|url+html}的意思是在格式化模板的時候,用格式化字典(fmap) 中"url+html" 關鍵字對應的函數的處理標簽的替代文本。這里的UrlHtmlFormatter 函數,只是為了安全啟見過濾包含的不合法信息。
這里的模板只是用于顯式的html頁面。如果覺得上面的解釋比較簡略的話,可以看到template包的 documentation。
我們僅僅用很少的代碼加一些HTML文本就實現了一個有意思的webserver。使用go,往往用很少的 代碼就能實現強大的功能。
- 1. 關于本文
- 2. Go語言簡介
- 3. 安裝go環境
- 3.1. 簡介
- 3.2. 安裝C語言工具
- 3.3. 安裝Mercurial
- 3.4. 獲取代碼
- 3.5. 安裝Go
- 3.6. 編寫程序
- 3.7. 進一步學習
- 3.8. 更新go到新版本
- 3.9. 社區資源
- 3.10. 環境變量
- 4. Go語言入門
- 4.1. 簡介
- 4.2. Hello,世界
- 4.3. 分號(Semicolons)
- 4.4. 編譯
- 4.5. Echo
- 4.6. 類型簡介
- 4.7. 申請內存
- 4.8. 常量
- 4.9. I/O包
- 4.10. Rotting cats
- 4.11. Sorting
- 4.12. 打印輸出
- 4.13. 生成素數
- 4.14. Multiplexing
- 5. Effective Go
- 5.1. 簡介
- 5.2. 格式化
- 5.3. 注釋
- 5.4. 命名
- 5.5. 分號
- 5.6. 控制流
- 5.7. 函數
- 5.8. 數據
- 5.9. 初始化
- 5.10. 方法
- 5.11. 接口和其他類型
- 5.12. 內置
- 5.13. 并發
- 5.14. 錯誤處理
- 5.15. Web服務器
- 6. 如何編寫Go程序
- 6.1. 簡介
- 6.2. 社區資源
- 6.3. 新建一個包
- 6.4. 測試
- 6.5. 一個帶測試的演示包
- 7. Codelab: 編寫Web程序
- 7.1. 簡介
- 7.2. 開始
- 7.3. 數據結構
- 7.4. 使用http包
- 7.5. 基于http提供wiki頁面
- 7.6. 編輯頁面
- 7.7. template包
- 7.8. 處理不存在的頁面
- 7.9. 儲存頁面
- 7.10. 錯誤處理
- 7.11. 模板緩存
- 7.12. 驗證
- 7.13. 函數文本和閉包
- 7.14. 試試!
- 7.15. 其他任務
- 8. 針對C++程序員指南
- 8.1. 概念差異
- 8.2. 語法
- 8.3. 常量
- 8.4. Slices(切片)
- 8.5. 構造值對象
- 8.6. Interfaces(接口)
- 8.7. Goroutines
- 8.8. Channels(管道)
- 9. 內存模型
- 9.1. 簡介
- 9.2. Happens Before
- 9.3. 同步(Synchronization)
- 9.4. 錯誤的同步方式
- 10. 附錄
- 10.1. 命令行工具
- 10.2. 視頻和講座
- 10.3. Release History
- 10.4. Go Roadmap
- 10.5. 相關資源